没有J2EE容器的JNDI和JPA

我们希望通过尽可能简单的设置来测试一些JPA代码。 计划仅使用Java和Maven,不使用应用程序服务器或其他J2EE容器。

我们的JPA配置需要两件事才能成功运行:

  • 数据库来存储数据,
  • JNDI访问数据库。

这篇文章分为两个部分。 第一部分显示了如何在测试中使用独立的JNDI和嵌入式内存数据库。 其余各章说明了该解决方案的工作方式。

所有使用的代码都可以在Github上找到 。 如果您对解决方案感兴趣,但不想阅读说明,请从Github下载项目,并仅阅读第一章。

JPA测试

本章说明如何在测试中使用我们的代码来启用独立的JNDI和嵌入式内存数据库。 本文的其余部分将说明该解决方案的工作方式和原因。

该解决方案具有三个“ API”类:

  • JNDIUtil – JNDI初始化,清理和一些便捷方法,
  • InMemoryDBUtil –数据库和数据源的创建/删除,
  • AbstractTestCase –在第一次测试之前清理数据库,在每次测试之前清理JNDI。

我们使用Liquibase维护数据库结构。 如果您不想使用Liquibase,则必须自定义InMemoryDBUtil类。 调整方法createDatabaseStructure以执行所需的操作。

Liquibase将所有需要的数据库更改的列表保存在名为changelog的文件中。 除非另行配置,否则每个更改仅运行一次。 即使将更改日志文件多次应用于同一数据库。

用法

AbstractTestCase扩展的任何测试用例都将:

  • 在第一次测试之前删除数据库,
  • 在每次测试之前安装独立的JNDI或删除其中存储的所有数据,
  • 每次测试之前,请对数据库运行Liquibase changelog。

JPA测试用例必须扩展AbstractTestCase并重写getInitialChangeLog方法。 该方法应返回changelog文件位置。

public class DemoJPATest extends AbstractTestCase {private static final String CHANGELOG_LOCATION = "src/test/java/org/meri/jpa/simplest/db.changelog.xml";private static EntityManagerFactory factory;public DemoJPATest() {}@Overrideprotected String getInitialChangeLog() {return CHANGELOG_LOCATION;}@Test@SuppressWarnings("unchecked")public void testJPA() {EntityManager em = factory.createEntityManager();Query query = em.createQuery("SELECT x FROM Person x");List<Person> allUsers = query.getResultList();em.close();assertFalse(allUsers.isEmpty());}@BeforeClasspublic static void createFactory() {factory = Persistence.createEntityManagerFactory("Simplest");}@AfterClasspublic static void closeFactory() {factory.close();}}

注意:在每次测试之前删除数据库会更清洁。 但是,删除和重新创建数据库结构是昂贵的操作。 这会大大降低测试用例的速度。 仅在上课之前这样做似乎是一种合理的妥协。

虽然数据库仅删除一次,但更改日志在每次测试之前运行。 可能看起来很浪费,但是此解决方案具有一些优势。 首先, getInitialChangeLog方法不必是静态的,并且可以在每个测试中覆盖。 其次,配置为“ runAlways”的更改将在每次测试之前运行,因此可能包含一些廉价的清理或其他初始化操作。

日本国家发展研究院

本章说明什么是JNDI,如何使用它以及如何配置它。 如果您对理论不感兴趣,请跳至下一章。 在此创建独立的JNDI。

基本用法

JNDI允许客户端通过名称存储和查找数据和对象。 通过接口Context的实现访问数据存储。

以下代码显示了如何在JNDI中存储数据:

Context ctx = new InitialContext();
ctx.bind("jndiName", "value");
ctx.close();

第二段代码显示了如何在JNDI中查找内容:

Context ctx = new InitialContext();
Object result = ctx.lookup("jndiName");
ctx.close();

尝试在没有J2EE容器的情况下运行以上代码,您将得到一个错误:

javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initialat javax.naming.spi.NamingManager.getInitialContext(Unknown Source)at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source)at javax.naming.InitialContext.bind(Unknown Source)at org.meri.jpa.JNDITestCase.test(JNDITestCase.java:16)at ...

该代码不起作用,因为InitialContext类不是真实的数据存储。 InitialContext类只能找到Context接口的另一个实例,并将所有工作委托给它。 它既无法存储数据也无法找到它们。

上下文工厂

真正的上下文,即完成所有工作并能够存储/查找数据的上下文,必须由上下文工厂创建。 本节说明如何创建上下文工厂以及如何配置InitialContext以使用它。

每个上下文工厂必须实现InitialContextFactory接口,并且必须具有无参数构造函数:

package org.meri.jpa.jndi;public class MyContextFactory implements InitialContextFactory {@Overridepublic Context getInitialContext(Hashtable environment) throws NamingException {return new MyContext();}}

我们的工厂返回一个简单的上下文,称为MyContext 。 其lookup方法始终返回字符串“存储值”:

class MyContext implements Context {@Overridepublic Object lookup(Name name) throws NamingException {return "stored value";}@Overridepublic Object lookup(String name) throws NamingException {return "stored value";}.. the rest ...
}

JNDI配置在哈希表中的类之间传递。 键始终包含属性名称,而值包含属性值。 由于初始上下文构造函数InitialContext()没有参数,因此假定为空哈希表。 该类还有一个替代构造函数,该构造函数将配置属性哈希表作为参数。

使用属性"java.naming.factory.initial"来指定上下文工厂类名称。 该属性在Context.INITIAL_CONTEXT_FACTORY常量中定义。

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "className");Context ctx = new InitialContext(environnement);

下一步测试配置MyContextFactory并检查创建的初始上下文是否返回“存储值”,无论如何:

@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
public void testDummyContext() throws NamingException {Hashtable environnement = new Hashtable();environnement.put(Context.INITIAL_CONTEXT_FACTORY, "org.meri.jpa.jndi.MyContextFactory");Context ctx = new InitialContext(environnement);Object value = ctx.lookup("jndiName");ctx.close();assertEquals("stored value", value);
}

当然,仅当您可以将具有自定义属性的哈希表提供给初始上下文构造函数时,此方法才有效。 这通常是不可能的。 大多数库使用开头所示的无参数构造函数。 他们假定初始上下文类具有可用的默认上下文工厂,并且无参数构造函数将使用该默认工厂。

命名经理

初始上下文使用NamingManager创建真实上下文。 命名管理器具有静态方法getInitialContext(Hashtable env) ,该方法返回上下文的实例。 参数env包含用于构建上下文的配置属性。

默认情况下,命名管理器从env哈希表中读取Context.INITIAL_CONTEXT_FACTORY并创建指定的初始上下文工厂的实例。 然后,工厂方法将创建一个新的上下文实例。 如果未设置该属性,则命名管理器将引发异常。

可以自定义命名管理员的行为。 NamingManager类具有setInitialContextFactoryBuilder方法。 如果设置了初始上下文工厂构建器,则命名管理器将使用它来创建上下文工厂。

您只能使用此方法一次。 已安装的上下文工厂生成器无法更改。

try {MyContextFactoryBuilder builder = new MyContextFactoryBuilder();NamingManager.setInitialContextFactoryBuilder(builder);
} catch (NamingException e) {// handle exception
}

初始上下文工厂构建器必须实现InitialContextFactoryBuilder接口。 界面很简单。 它只有一个方法InitialContextFactory createInitialContextFactory(Hashtable env)

摘要

简而言之,初始上下文将实际的上下文初始化委托给命名管理器,命名管理器将其委托给上下文工厂。 上下文工厂由初始上下文工厂构建器的实例创建。


独立JNDI

我们将创建并安装独立的JNDI实现。 我们的独立JNDI实现的入口点是JNDIUtil类。

在没有应用程序服务器的情况下启用JNDI需要三件事:

  • ContextInitialContextFactory接口的实现,
  • InitialContextFactoryBuilder接口的实现,
  • 初始上下文工厂构建器的安装以及清除所有存储数据的能力。

上下文和工厂

我们从osjava项目中获取了SimpleJNDI实现,并对其进行了修改以更好地满足我们的需求。 该项目使用了新的BSD许可证 。

将SimpleJNDI maven依赖项添加到pom.xml中:

simple-jndisimple-jndi0.11.4.1

SimpleJNDI带有一个MemoryContext上下文,该上下文仅位于内存中。 它几乎不需要任何配置,并且其状态永远不会保存下来。 它几乎满足了我们的需求,除了两件事:

  • 它的close()方法删除所有存储的数据,
  • 每个实例默认使用其自己的存储。

大多数库都假定close方法优化了资源。 他们倾向于在每次加载或存储数据时调用它。 如果close方法在存储完所有数据后立即删除它们,则上下文将无用。 我们必须扩展MemoryContext类并重写close方法:

@SuppressWarnings({"rawtypes"}) 
public class CloseSafeMemoryContext extends MemoryContext {public CloseSafeMemoryContext(Hashtable env) {super(env);}@Overridepublic void close() throws NamingException {// Original context lost all data on close();// That made it unusable for my tests. }}

按照约定,建造者/工厂系统会为每次使用创建新的上下文实例。 如果它们不共享数据,则不能使用JNDI在不同库之间传输数据。

幸运的是,这个问题也很容易解决。 如果环境哈希表包含值为"true"属性"org.osjava.sj.jndi.shared" "true" ,则创建的内存上下文将使用公共静态存储。 因此,我们的初始上下文工厂将创建CloseSafeMemoryContext实例,并将其配置为使用公共存储:

public class CloseSafeMemoryContextFactory implements InitialContextFactory {private static final String SHARE_DATA_PROPERTY = "org.osjava.sj.jndi.shared";public Context getInitialContext(Hashtable environment) throws NamingException {// clone the environnementHashtable sharingEnv = (Hashtable) environment.clone();// all instances will share stored dataif (!sharingEnv.containsKey(SHARE_DATA_PROPERTY)) {sharingEnv.put(SHARE_DATA_PROPERTY, "true");}return new CloseSafeMemoryContext(sharingEnv);;}}

初始上下文工厂生成器

我们的构建器的行为几乎与原始命名管理器实现相同。 如果传入环境中存在属性Context.INITIAL_CONTEXT_FACTORY ,则将创建指定的工厂。

但是,如果缺少此属性,则构建器将创建CloseSafeMemoryContextFactory的实例。 原始的命名管理器将引发异常。

我们对InitialContextFactoryBuilder接口的实现:

public InitialContextFactory createInitialContextFactory(Hashtable env) throws NamingException {String requestedFactory = null;if (env!=null) {requestedFactory = (String) env.get(Context.INITIAL_CONTEXT_FACTORY);}if (requestedFactory != null) {return simulateBuilderlessNamingManager(requestedFactory);}return new CloseSafeMemoryContextFactory();
}

方法simulateBuilderlessNamingManager使用类加载器加载请求的上下文工厂:

private InitialContextFactory simulateBuilderlessNamingManager(String requestedFactory) throws NoInitialContextException {try {ClassLoader cl = getContextClassLoader();Class requestedClass = Class.forName(className, true, cl);return (InitialContextFactory) requestedClass.newInstance();} catch (Exception e) {NoInitialContextException ne = new NoInitialContextException(...);ne.setRootCause(e);throw ne;}
}private ClassLoader getContextClassLoader() {return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {public Object run() {return Thread.currentThread().getContextClassLoader();}});
}

构建器安装和上下文清理

最后,我们必须安装上下文工厂生成器。 当我们想在测试中使用独立的JNDI时,我们还需要一种方法来清除测试之间的所有存储数据。 两者都在initializeJNDI方法内部完成,该方法将在每次测试之前运行:

public class JNDIUtil {public void initializeJNDI() {if (jndiInitialized()) {cleanAllInMemoryData();} else {installDefaultContextFactoryBuilder();}}}

如果已经设置了默认上下文工厂生成器,那么将初始化JNDI:

private boolean jndiInitialized() {return NamingManager.hasInitialContextFactoryBuilder();}

安装默认上下文工厂生成器:

private void installDefaultContextFactoryBuilder() {try {NamingManager.setInitialContextFactoryBuilder(new ImMemoryDefaultContextFactoryBuilder());} catch (NamingException e) {//We can not solve the problem. We will let it go up without//having to declare the exception every time.throw new ConfigurationException(e);}
}

使用原始的方法实现closeMemoryContext类清理存储数据:

private void cleanAllInMemoryData() {CleanerContext cleaner = new CleanerContext();try {cleaner.close();} catch (NamingException e) {throw new RuntimeException("Memory context cleaning failed:", e);}
}class CleanerContext extends MemoryContext {private static Hashtable environnement = new Hashtable();static {environnement.put("org.osjava.sj.jndi.shared", "true");}public CleanerContext() {super(environnement);}}


内存数据库

Apache Derby是用Java实现的开源关系数据库。 根据Apache许可证2.0版提供。 Derby能够以嵌入式模式运行。 嵌入式数据库数据存储在文件系统或内存中。

对Derby的Maven依赖关系:

org.apache.derbyderby10.8.2.2

创建数据源

使用EmbeddedDatasource类的实例连接到数据库。 每当数据库名称以“ memory:”开头时,数据源将使用一个内存中实例。

以下代码创建指向内存数据库实例的数据源。 如果数据库尚不存在,将创建它:

private EmbeddedDataSource createDataSource() {EmbeddedDataSource dataSource = new EmbeddedDataSource();dataSource.setDataSourceName(dataSourceJndiName);dataSource.setDatabaseName("memory:" + databaseName);dataSource.setCreateDatabase("create");return dataSource;
}

删除数据库

清理数据库的最简单方法是删除并重新创建它。 创建嵌入式数据源的实例,将连接属性“ drop”设置为“ true”,并调用其getConnection方法。 它将删除数据库并引发异常。

private static final String DATABASE_NOT_FOUND = "XJ004";private void dropDatabase() {EmbeddedDataSource dataSource = createDataSource();dataSource.setCreateDatabase(null);dataSource.setConnectionAttributes("drop=true");try {//drop the database; not the nicest solution, but worksdataSource.getConnection();} catch (SQLNonTransientConnectionException e) {//this is OK, database was dropped} catch (SQLException e) {if (DATABASE_NOT_FOUND.equals(e.getSQLState())) {//attempt to drop non-existend database//we will ignore this errorreturn ; }throw new ConfigurationException("Could not drop database.", e);}}


数据库结构

我们使用Liquibase创建数据库结构和测试数据。 数据库结构保存在所谓的变更日志文件中。 它是一个xml文件,但是如果您不想学习另一种xml语言,则可以包含DDL或SQL代码。

Liquibase及其优点不在本文讨论范围之内。 此演示最相关的优势是它能够对同一数据库多次运行同一变更日志。 每次运行仅将新更改应用于数据库。 如果文件未更改,则什么都不会发生。

您可以将更改日志添加到jar或war中,并在每次启动应用程序时运行它。 这样可以确保数据库始终更新为最新版本。 无需配置或安装脚本。

将Liquibase依赖项添加到pom.xml:

org.liquibaseliquibase-core2.0.3

在更新日志之后,将创建一个名为Person的表,并将一个条目“斜杠– Simon Worth”放入其中:

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.9
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd"><changeSet id="1" author="meri"><comment>Create table structure for users and shared items.</comment><createTable tableName="person"><column name="user_id" type="integer"><constraints primaryKey="true" nullable="false" /></column><column name="username" type="varchar(1500)"><constraints unique="true" nullable="false" /></column><column name="firstname" type="varchar(1500)"/><column name="lastname" type="varchar(1500)"/><column name="homepage" type="varchar(1500)"/><column name="about" type="varchar(1500)"/></createTable></changeSet><changeSet id="2" author="meri" context="test"><comment>Add some test data.</comment><insert tableName="person"><column name="user_id" valueNumeric="1" /><column name="userName" value="slash" /><column name="firstName" value="Simon" /><column name="lastName" value="Worth" /><column name="homePage" value="http://www.slash.blogs.net" /><column name="about" value="I like nature and writing my blog. The blog contains my opinions about everything." /></insert></changeSet></databaseChangeLog>

Liquibase的使用非常简单。 使用数据源创建新的Liquibase实例,运行其update方法并处理所有声明的异常:

private void initializeDatabase(String changelogPath, DataSource dataSource) {try {//create new liquibase instanceConnection sqlConnection = dataSource.getConnection();DatabaseConnection db = new DerbyConnection(sqlConnection);Liquibase liquibase = new Liquibase(changelogPath, new FileSystemResourceAccessor(), db);//update the databaseliquibase.update("test");} catch (SQLException e) {// We can not solve the problem. We will let it go up without// having to declare the exception every time.throw new ConfigurationException(DB_INITIALIZATION_ERROR, e);} catch (LiquibaseException e) {// We can not solve the problem. We will let it go up without// having to declare the exception every time.throw new ConfigurationException(DB_INITIALIZATION_ERROR, e);}}


结束

每次我们运行测试时,独立的JNDI数据库和嵌入式内存数据库都已启动并正在运行。 尽管JNDI设置可能是通用的,但数据库的构建可能需要对项目进行特定的修改。

可以从Github上免费下载示例项目,并使用/修改任何有用的内容。

参考: This is Stuff博客上的JCG合作伙伴 Maria Jurcovicova的JNDI和JPA Without J2EE Con​​tainer运行 。


翻译自: https://www.javacodegeeks.com/2012/04/jndi-and-jpa-without-j2ee-container.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372986.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

string 大小写转换

STL的algorithm库确实给我们提供了这样的便利&#xff0c;使用模板函数transform可以轻松解决这个问题&#xff0c;开发人员只需要提供一个函数对象&#xff0c;例如将char转成大写的toupper函数或者小写的函数tolower函数。 transform原型&#xff1a; 1 #include <string&…

linux服务器上svn的log_如何在 Centos 8 / RHEL 8 上安装和配置 VNC 服务器 | Linux 中国...

在 Centos 8 和 RHEL 8 系统中&#xff0c;默认未安装 VNC 服务器&#xff0c;它需要手动安装。在本文中&#xff0c;我们将通过简单的分步指南&#xff0c;介绍如何在 Centos 8 / RHEL 8 上安装 VNC 服务器。-- Pradeep KumarVNC(虚拟网络计算Virtual Network Computing)服务器…

怎么把网页保存到本地计算机,在IE浏览器中,将网页保存到本地计算机中,若只需保存其中的文字、超链接和表格信息,应该选择的保存类型为( )...

2.(2017高一上东台月考)阅读下面一段资料&#xff0c;判断在给出的几种说法中不正确的是( )资料&#xff1a;IP电话与传统电话IP电话是按国际互联网协议规定的网络技术内容开通的电话业务&#xff0c;中文翻译为网络电话或互联网电话&#xff0c;它是利用国际互联网Inetrnet为…

html_博客博主

csdn: 工匠若水 http://blog.csdn.net/yanbober yunama: IT蓝豹&#xff1a;http://www.itlanbao.com/&#xff1b; http://ask.dcloud.net.cn/docs/; 博客园&#xff1a; https://www.cnblogs.com/guweiwei/category/965437.html转载于:https://www.cnblogs.com/awkflf11/p/55…

Windows上的Java线程CPU分析

本文将为您提供一个教程&#xff0c;介绍如何在Windows OS上快速查明Java线程贡献者与CPU严重问题有关。 Windows与Linux&#xff0c;Solaris和AIX等其他操作系统一样&#xff0c;使您可以在进程级别监视CPU利用率&#xff0c;还可以监视在进程中执行任务的单个线程。 在本教程…

flask 继承模版的基本使用1

转载于:https://www.cnblogs.com/wanghaonull/p/6399492.html

东芝2303am维护清零_东芝打印机2303A怎样清零

展开全部东芝e68a843231313335323631343130323136353331333365653137打印机是按照相关要求生产的正规产品&#xff0c;其清零方式与正规产品相同。因此此处将介绍常用的打印机清零方法。打印机清零一般分两种&#xff1a;一种是手工清零&#xff0c;另一种是软件清零。一、手工…

计算机日期函数公式大全,Excel技巧: 根据日期汇总月份的计算公式

在许多情况下&#xff0c;Excel记录的数据将按照发生的日期进行记录&#xff0c;但是根据日期记录的数据将非常分散&#xff0c;通常需要每月汇总相应的数据. 在这种情况下&#xff0c;您需要将日期转换为月份. 本文介绍了如何使用SUMPRODUCT函数按月汇总数据.公式提示在SUMPRO…

Java陷阱:内部类中的字段访问

这本身不是一个“陷阱”&#xff0c;而是一个值得了解的实现细节。 假设我有一个带有字段的内部类。 这样的字段对于封闭的类是可见的&#xff0c;但是以下哪种方法是访问它的最快方法&#xff1f; 注意&#xff01; 我只在这里查看生成的字节码&#xff0c;而不考虑任何JIT优化…

coverity代码检测工具介绍_微服务测试之静态代码扫描

静态代码扫描为整个发展组织增加价值。无论您在开发组织中发挥的作用如何&#xff0c;静态代码扫描解决方案都具有附加价值&#xff0c;拥有软件开发中所需要的尖端功能&#xff0c;最大限度地提高质量并管理软件产品中的风险。背景微服务架构模式具有服务间独立&#xff0c;可…

XML引入以及与html的区别

1.1 引入HTML: 负责网页的结构 CSS&#xff1a; 负责网页的样式&#xff08;美观&#xff09;Javascript&#xff1a; 负责在浏览器端与用户进行交互。负责静态的网页制作的语言HTML语言特点&#xff1a;1&#xff09;由标签组成。 <title> <p> <hr/> <br…

ADF:在任务流终结器中支持bean作用域

介绍 当我们需要在任务流消失之前完成一些最终工作&#xff08;干净的资源&#xff0c;紧密的连接等&#xff09;时&#xff0c;这是使用任务流终结器的非常普遍的推荐做法。 和往常一样&#xff0c;我们使用在任务流中声明的托管bean。 托管Bean可以具有不同的范围-请求&#…

Python 异常处理--raise函数用法

在Python中&#xff0c;要想引发异常&#xff0c;最简单的形式就是输入关键字raise&#xff0c;后跟要引发的异常的名称。异常名称标识出具体的类&#xff1a; Python异常处理是那些类的对象。执行raise语句时&#xff0c;Python会创建指定的异常类的一个对象。raise语句还可指…

大学计算机教学ppt数制,大学计算机基础 第3讲 数制及其相互转换 国家精品课程课件(可编辑)...

大学计算机基础第3讲数制及其相互转换国家精品课程课件PPT第1 章计算机基础知识第3 讲数制及其相互转换主要教学内容数制的基本概念1 数制转换2 小结3 学习目标1 理解数制的基本概念。2 掌握数制间的转换。3 能够灵活应用转换关系完成数制之间的转换。重点与难点不同数制之间的…

linux中匿名用户怎么登陆_南京课工场IT培训:Linux中vsftpd服务配置(匿名,用户,虚拟用户)...

vsftpd概述vsftpd 是“very secure FTP daemon”的缩写&#xff0c;安全性是它的一个最大的特点。vsftpd 是一个 UNIX 类操作系统上运行的服务器的名字&#xff0c;它可以运行在诸如 Linux、BSD、Solaris、 HP-UNIX等系统上面&#xff0c;是一个完全免费的、开放源代码的ftp服务…

Java _ JDK _ Arrays, LinkedList, ArrayList, Vector 及Stack

(最近在看JDK源码&#xff0c;只是拿着它的继承图在看&#xff0c;但很多东西不记录仍然印象不深&#xff0c;所以开始记录JDK阅读系列。) &#xff08;一&#xff09;Arrays Arrays比较特殊&#xff0c;直接继承自Arrays -》List(Interface) -》Collection(Interface)。(Maybe…

server2016做文件服务器,『配置』服务器搭建 Office Online Server2016 实现文档预览 番外 错误篇...

安装一个或多个角色、角色服务或功能失败。找不到源文件。请再次尝试在新的“添加角色和功能”向导会话中安装角色、角色服务或功能&#xff0c;然后在向导的“确认”页中单击“指定备用源路径”以指定安装所需的源文件的有效位置。目标服务器的计算机帐户必须能够访问该位置。…

Java High CPU故障排除指南–第1部分

本文是该系列的第1部分&#xff0c;它将为您提供有关如何进行故障排除和识别Java高CPU问题根本原因的综合指南。 该指南也适用于独立的Java程序&#xff0c;但旨在帮助涉及Java EE企业日常生产支持的个人。 它还将包括最常见的高级CPU问题列表以及高级解决方案。 生产问题解决…

PHP数据结构之三 线性表中的单链表的PHP实现

线性表的链式存储&#xff1a;用一组任意的存储单元存储线性表中的数据元素。用这种方法存储的线性表简称线性链表。 链式存储线性表的特点&#xff1a;存储链表中结点的一组任意的存储单元可以是连续的&#xff0c;也可以是不连续的&#xff0c;甚至是零散分布在内存中的任意位…

php进程间通信 yoc_swoole的process模块创建和使用子进程

swoole中为我们提供了一个进程管理模块 Process&#xff0c;替换PHP的 pcntl 扩展&#xff0c;方便我们创建进程&#xff0c;管理进程&#xff0c;和进程间的通信。swoole提供了2种进程间的通信&#xff1a;1、基于 unix socket 的管道 pipe。2、基于 sysvmsg 的消息队列。我们…