无法查找 JNDI 名称 [jdbc/jbpm-ds]
Unable to lookup JNDI name [jdbc/jbpm-ds]
我正在尝试开发 jBPM spring 引导应用程序,但出现无法查找 JNDI 名称 [jdbc/jbpm-ds] 错误。
为此,我使用了 jbpm-7.36.0.Final、Spring-Boot-2.2.6 和 jbpm-spring-boot 7.36.0 Final 以及 spring 启动 Bitronix api。下面是我的pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-bitronix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<!-- <version>5.2.6.RELEASE</version> -->
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>jbpm-spring-boot-starter-basic</artifactId>
<version>${runtime.version}</version>
</dependency>
</dependencies>
在我的 application.properties 文件中,我配置了以下值
#hibernate configuration
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.hbm2ddl.auto=update
#JTA enabled
spring.jta.enabled=true
#bitronix Non-XA transaction manager configuration
spring.datasource.xa.properties.url=jdbc:sqlserver://10.1.5.209:1433;databaseName=MRR3;
spring.datasource.xa.properties.uniqueName=jdbc/jbpm-ds
spring.datasource.xa.properties.username=sa
spring.datasource.xa.properties.password=password_123
spring.datasource.xa.properties.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.xa.data-source-class-name=bitronix.tm.resource.jdbc.lrc.LrcXADataSource
下面是代码片段
@Bean
public StatefulKnowledgeSession newStatefulKnowledgeSession() throws Exception {
RuntimeEnvironmentBuilder builder = null;
if (usePersistence) {
TransactionManager tm = TransactionManagerServices.getTransactionManager();
entityManagerFactory = Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa");//Line where Exception occurs
System.out.println(entityManagerFactory.getProperties());
Environment env = EnvironmentFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, entityManagerFactory);
env.set(EnvironmentName.TRANSACTION_MANAGER, tm);
builder = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
.entityManagerFactory(entityManagerFactory)
.addEnvironmentEntry(EnvironmentName.TRANSACTION_MANAGER, tm);
builder.knowledgeBase(readKnowledgeBase);
StatefulKnowledgeSession ksession = JPAKnowledgeService
.newStatefulKnowledgeSession(readKnowledgeBase, null, env);
return ksession;
// builder =
// RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
// .entityManagerFactory(entityManagerFactory);
}
}
分享重要的日志信息
2020-05-11 23:41:12.122 INFO 18852 --- [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: org.jbpm.persistence.jpa
...] {} <>
2020-05-11 23:41:12.155 WARN 18852 --- [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'newStatefulKnowledgeSession' defined in class path resource [com/citiustech/mrr/controller/AbstractionProcessController.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.kie.internal.runtime.StatefulKnowledgeSession]: Factory method 'newStatefulKnowledgeSession' threw exception; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] {} <>
.
.
.
Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:275)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:179)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:119)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:904)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:935)
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
at com.citiustech.mrr.controller.AbstractionProcessController.newStatefulKnowledgeSession(AbstractionProcessController.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 20 common frames omitted
Caused by: org.hibernate.engine.jndi.JndiException: Unable to lookup JNDI name [jdbc/jbpm-ds]
at org.hibernate.engine.jndi.internal.JndiServiceImpl.locate(JndiServiceImpl.java:100)
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.configure(DatasourceConnectionProviderImpl.java:98)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:100)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:246)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.buildJdbcConnectionAccess(JdbcEnvironmentInitiator.java:145)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:66)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:94)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
... 39 common frames omitted
Caused by: javax.naming.NameNotFoundException: unable to find a bound object at name 'jdbc/jbpm-ds'
at bitronix.tm.jndi.BitronixContext.lookup(BitronixContext.java:83)
at bitronix.tm.jndi.BitronixContext.lookup(BitronixContext.java:67)
at javax.naming.InitialContext.lookup(InitialContext.java:421)
at org.hibernate.engine.jndi.internal.JndiServiceImpl.locate(JndiServiceImpl.java:97)
... 48 common frames omitted
我也很想知道我的以下理解是否正确
- jBPM 只支持 JTA 类型的事务,即全局事务。集成 jBPM 时不能使用 RESOURCE_LOCAL 事务类型。
- 当我说事务类型 RESOURCE_LOCAL 时,意味着只有一个数据源事务将在应用程序中共享。
- jBPM RuntimeManager 使用 'org.jbpm.domain' 持久化单元名称(强制类型)来处理它所有的内部 table 操作。
- 所有特定于应用程序的事务都可以由默认的持久性单元名称处理,即'org.jbpm.persistence.jpa'。这可以被自定义持久性上下文覆盖。
- JTA又分为XADatasource类型和Non-XADatasource类型两种。当数据源位于应用程序服务器容器中时,应使用 XADatasource。 Non-XADatasource 对于基于 EJB 的应用程序很有用。
以下配置需要 XADatasource
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
和
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.WeblogicJtaPlatform" />
以下配置需要非 XADatasource
<provider>org.hibernate.ejb.HibernatePersistence</provider>
和
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
是否需要第 6 点或第 7 点,如果是,如何不使用 persistence.xml。
下面的有什么用属性什么jar有这个class
spring.jpa.properties.hibernate.transaction.manager_lookup_class=org.hibernate.transaction.BTMTransactionManagerLookup
有一些误解:
- jbpm-spring-boot-starter-basic 正在使用,但是您没有使用任何 spring 加载的 bean 来创建您的 StatefulKnowledgeSession。 starter 的主要思想是避免低级框架配置。
- 这个参数:spring.datasource.xa.properties.uniqueName没有出现在文档中,是驼峰式。
解决方案 1:Spring 启动
使用正式版及其配置
#data source configuration
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.url=jdbc:h2:./target/spring-boot-jbpm;MVCC=true
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.type=org.apache.tomcat.jdbc.pool.XADataSource
#hibernate configuration
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
#transaction manager configuration
spring.jta.narayana.transaction-manager-id=1
我们可以看到,jbpm-spring-boot-starter-basic依赖于spring-boot 没有任何 new 数据库配置的数据源引擎。为什么?因为 StatefulKnowledgeSession 只需要一个经典的数据库连接。
也许这个启动器初始化一个 StatefulKnowledgeSession 准备好在任何 spring java bean 中使用 @Autowire
解决方案 2:Spring + 手动配置
一个简单的研究告诉我,要从 JPAKnowledgeService 创建一个 StatefulKnowledgeSession 需要经典的:
EntityManagerFactory and TransactionManager
- https://docs.jboss.org/jbpm/v5.1/javadocs/org/drools/persistence/jpa/JPAKnowledgeService.html(查看 java文档)
- https://github.com/kiegroup/droolsjbpm-knowledge/blob/master/kie-internal/src/main/java/org/kie/internal/persistence/jpa/JPAKnowledgeService.java
在您的代码中也看到了这一点:
Environment env = EnvironmentFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, entityManagerFactory);
env.set(EnvironmentName.TRANSACTION_MANAGER, tm);
在这个例子中:
public static class JpaConfiguration {
private EntityManagerFactory emf;
private PlatformTransactionManager tm;
}
//..
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY,
jpaConfiguration.getEntityManagerFactory() );
env.set( EnvironmentName.TRANSACTION_MANAGER,
jpaConfiguration.getPlatformTransactionManager() );
所以解决方案可能只是配置一个 spring 启动以拥有优雅的自动装配:
//@SpringBootApplication or @Configuration
public class SpringMainApplication{
@Autowire
private EntityManagerFactory emf;
@Autowire
private PlatformTransactionManager tm;
@Autowire
private KnowledgeBase kbase;
@Bean
public KnowledgeBase readKnowledgeBase() throws Exception {
List<RuleResource> resources = new ArrayList<RuleResource>();
resources.add(new RuleResource("zzz/explore/ruleengine/rules/CalcPI.drl", ResourceType.DRL));
return KnowledgeBaseHelper.readKnowledgeBase(resources);
}
@Bean
public StatefulKnowledgeSession newStatefulKnowledgeSession() throws Exception {
//if KnowledgeBase autowire does not works, just call directly
//KnowledgeBase kbase = readKnowledgeBase();
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
env.set( EnvironmentName.TRANSACTION_MANAGER,tm);
StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession(kbase, null, env);
return ksession;
}
}
现在,我们需要配置 spring 启动此实例以供使用:
@Autowire
private EntityManagerFactory emf;
@Autowire
private PlatformTransactionManager tm;
我们可以这样做:
//@SpringBootApplication or @Configuration
class SpringMainApplication {
//spring boo twill auto-provide a Bean of type DataSource
// if the properties are there
@Autowired
private DataSource dataSource;
@Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.acme.domain");
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
}
有很多文档和示例可以创建 EntityManagerFactory 和 TransactionManager。检查参考部分。
另外,如果你正确使用启动器,也许不需要这些配置
解决方案 3:手动创建实例
如您所见,只需要实体管理器和事务管理器。此外,要创建一个实体管理器,还需要一个有效的数据源。所以你只需要像这样的东西:
//@SpringBootApplication or @Configuration
public class SpringMainApplication{
@Bean
public KnowledgeBase readKnowledgeBase() throws Exception {
List<RuleResource> resources = new ArrayList<RuleResource>();
resources.add(new RuleResource("zzz/explore/ruleengine/rules/CalcPI.drl", ResourceType.DRL));
return KnowledgeBaseHelper.readKnowledgeBase(resources);
}
@Bean
public StatefulKnowledgeSession newStatefulKnowledgeSession() throws Exception {
//Crete datasource
//https://gist.github.com/jrichardsz/8b8dffcf1cdf42444654abc227d9f4c1
//or use the spring provided datasource
//create an entity manger
EntityManagerFactory emf = ...;
//create an transaction manger
PlatformTransactionManager tm =....;
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
env.set( EnvironmentName.TRANSACTION_MANAGER,tm);
StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession(kbase, null, env);
return ksession;
}
}
}
备注
这些片段没有经过测试,因为 drools 和数据库不容易配置,而且您没有共享最小的可运行示例。
我会加上这个研究的httplink
参考资料
- create datasource
- create datasource
- create datasource
- autowire datasource
- configure entitymanager and transaction manager
- configure entitymanager and transaction manager
- create knowledgebase
- create knowledgebase
- create knowledgebase
- JPAKnowledgeService
- JPAKnowledgeService
- JPAKnowledgeService
- JPAKnowledgeService
- JPAKnowledgeService
- JPAKnowledgeService
- spring boot starters
- spring boot starters
- StatefulKnowledgeSession
- StatefulKnowledgeSession
根据@JRichardsz 的建议,我对我的代码进行了以下更改以使其与 Spring Boot
一起使用
@Autowired
private AbstractPlatformTransactionManager jtaPlatform;
@PersistenceUnit(name = "org.jbpm.persistence.jpa")
private EntityManagerFactory entityManagerFactory;
@Bean
public StatefulKnowledgeSession newStatefulKnowledgeSession() throws Exception {
RuntimeEnvironmentBuilder builder = null;
if (usePersistence) {
builder = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
.entityManagerFactory(entityManagerFactory)
.addEnvironmentEntry(EnvironmentName.TRANSACTION_MANAGER, jtaPlatform);
builder.knowledgeBase(readKnowledgeBase);
RuntimeManager manager = RuntimeManagerFactory.Factory.get().newSingletonRuntimeManager(builder.get());
return (StatefulKnowledgeSession) manager.getRuntimeEngine(EmptyContext.get())
.getKieSession();
}
}
对我来说 xa.properties 与 Bitronix 一起工作,但如果它不适合你那么你可以切换到 Spring 提供的数据源。
我正在尝试开发 jBPM spring 引导应用程序,但出现无法查找 JNDI 名称 [jdbc/jbpm-ds] 错误。
为此,我使用了 jbpm-7.36.0.Final、Spring-Boot-2.2.6 和 jbpm-spring-boot 7.36.0 Final 以及 spring 启动 Bitronix api。下面是我的pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-bitronix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<!-- <version>5.2.6.RELEASE</version> -->
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>jbpm-spring-boot-starter-basic</artifactId>
<version>${runtime.version}</version>
</dependency>
</dependencies>
在我的 application.properties 文件中,我配置了以下值
#hibernate configuration
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.hbm2ddl.auto=update
#JTA enabled
spring.jta.enabled=true
#bitronix Non-XA transaction manager configuration
spring.datasource.xa.properties.url=jdbc:sqlserver://10.1.5.209:1433;databaseName=MRR3;
spring.datasource.xa.properties.uniqueName=jdbc/jbpm-ds
spring.datasource.xa.properties.username=sa
spring.datasource.xa.properties.password=password_123
spring.datasource.xa.properties.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.xa.data-source-class-name=bitronix.tm.resource.jdbc.lrc.LrcXADataSource
下面是代码片段
@Bean
public StatefulKnowledgeSession newStatefulKnowledgeSession() throws Exception {
RuntimeEnvironmentBuilder builder = null;
if (usePersistence) {
TransactionManager tm = TransactionManagerServices.getTransactionManager();
entityManagerFactory = Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa");//Line where Exception occurs
System.out.println(entityManagerFactory.getProperties());
Environment env = EnvironmentFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, entityManagerFactory);
env.set(EnvironmentName.TRANSACTION_MANAGER, tm);
builder = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
.entityManagerFactory(entityManagerFactory)
.addEnvironmentEntry(EnvironmentName.TRANSACTION_MANAGER, tm);
builder.knowledgeBase(readKnowledgeBase);
StatefulKnowledgeSession ksession = JPAKnowledgeService
.newStatefulKnowledgeSession(readKnowledgeBase, null, env);
return ksession;
// builder =
// RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
// .entityManagerFactory(entityManagerFactory);
}
}
分享重要的日志信息
2020-05-11 23:41:12.122 INFO 18852 --- [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: org.jbpm.persistence.jpa
...] {} <>
2020-05-11 23:41:12.155 WARN 18852 --- [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'newStatefulKnowledgeSession' defined in class path resource [com/citiustech/mrr/controller/AbstractionProcessController.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.kie.internal.runtime.StatefulKnowledgeSession]: Factory method 'newStatefulKnowledgeSession' threw exception; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] {} <>
.
.
.
Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:275)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:237)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory.injectServices(DefaultIdentifierGeneratorFactory.java:152)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.injectDependencies(AbstractServiceRegistryImpl.java:286)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:243)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:179)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:119)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:904)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:935)
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
at com.citiustech.mrr.controller.AbstractionProcessController.newStatefulKnowledgeSession(AbstractionProcessController.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 20 common frames omitted
Caused by: org.hibernate.engine.jndi.JndiException: Unable to lookup JNDI name [jdbc/jbpm-ds]
at org.hibernate.engine.jndi.internal.JndiServiceImpl.locate(JndiServiceImpl.java:100)
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.configure(DatasourceConnectionProviderImpl.java:98)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:100)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:246)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:214)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.buildJdbcConnectionAccess(JdbcEnvironmentInitiator.java:145)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:66)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:94)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
... 39 common frames omitted
Caused by: javax.naming.NameNotFoundException: unable to find a bound object at name 'jdbc/jbpm-ds'
at bitronix.tm.jndi.BitronixContext.lookup(BitronixContext.java:83)
at bitronix.tm.jndi.BitronixContext.lookup(BitronixContext.java:67)
at javax.naming.InitialContext.lookup(InitialContext.java:421)
at org.hibernate.engine.jndi.internal.JndiServiceImpl.locate(JndiServiceImpl.java:97)
... 48 common frames omitted
我也很想知道我的以下理解是否正确
- jBPM 只支持 JTA 类型的事务,即全局事务。集成 jBPM 时不能使用 RESOURCE_LOCAL 事务类型。
- 当我说事务类型 RESOURCE_LOCAL 时,意味着只有一个数据源事务将在应用程序中共享。
- jBPM RuntimeManager 使用 'org.jbpm.domain' 持久化单元名称(强制类型)来处理它所有的内部 table 操作。
- 所有特定于应用程序的事务都可以由默认的持久性单元名称处理,即'org.jbpm.persistence.jpa'。这可以被自定义持久性上下文覆盖。
- JTA又分为XADatasource类型和Non-XADatasource类型两种。当数据源位于应用程序服务器容器中时,应使用 XADatasource。 Non-XADatasource 对于基于 EJB 的应用程序很有用。
以下配置需要 XADatasource
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
和
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" /> <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.WeblogicJtaPlatform" />
以下配置需要非 XADatasource
<provider>org.hibernate.ejb.HibernatePersistence</provider>
和
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
是否需要第 6 点或第 7 点,如果是,如何不使用 persistence.xml。
下面的有什么用属性什么jar有这个class
spring.jpa.properties.hibernate.transaction.manager_lookup_class=org.hibernate.transaction.BTMTransactionManagerLookup
有一些误解:
- jbpm-spring-boot-starter-basic 正在使用,但是您没有使用任何 spring 加载的 bean 来创建您的 StatefulKnowledgeSession。 starter 的主要思想是避免低级框架配置。
- 这个参数:spring.datasource.xa.properties.uniqueName没有出现在文档中,是驼峰式。
解决方案 1:Spring 启动
使用正式版及其配置
#data source configuration
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.url=jdbc:h2:./target/spring-boot-jbpm;MVCC=true
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.type=org.apache.tomcat.jdbc.pool.XADataSource
#hibernate configuration
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
#transaction manager configuration
spring.jta.narayana.transaction-manager-id=1
我们可以看到,jbpm-spring-boot-starter-basic依赖于spring-boot 没有任何 new 数据库配置的数据源引擎。为什么?因为 StatefulKnowledgeSession 只需要一个经典的数据库连接。
也许这个启动器初始化一个 StatefulKnowledgeSession 准备好在任何 spring java bean 中使用 @Autowire
解决方案 2:Spring + 手动配置
一个简单的研究告诉我,要从 JPAKnowledgeService 创建一个 StatefulKnowledgeSession 需要经典的:
EntityManagerFactory and TransactionManager
- https://docs.jboss.org/jbpm/v5.1/javadocs/org/drools/persistence/jpa/JPAKnowledgeService.html(查看 java文档)
- https://github.com/kiegroup/droolsjbpm-knowledge/blob/master/kie-internal/src/main/java/org/kie/internal/persistence/jpa/JPAKnowledgeService.java
在您的代码中也看到了这一点:
Environment env = EnvironmentFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, entityManagerFactory);
env.set(EnvironmentName.TRANSACTION_MANAGER, tm);
在这个例子中:
public static class JpaConfiguration {
private EntityManagerFactory emf;
private PlatformTransactionManager tm;
}
//..
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY,
jpaConfiguration.getEntityManagerFactory() );
env.set( EnvironmentName.TRANSACTION_MANAGER,
jpaConfiguration.getPlatformTransactionManager() );
所以解决方案可能只是配置一个 spring 启动以拥有优雅的自动装配:
//@SpringBootApplication or @Configuration
public class SpringMainApplication{
@Autowire
private EntityManagerFactory emf;
@Autowire
private PlatformTransactionManager tm;
@Autowire
private KnowledgeBase kbase;
@Bean
public KnowledgeBase readKnowledgeBase() throws Exception {
List<RuleResource> resources = new ArrayList<RuleResource>();
resources.add(new RuleResource("zzz/explore/ruleengine/rules/CalcPI.drl", ResourceType.DRL));
return KnowledgeBaseHelper.readKnowledgeBase(resources);
}
@Bean
public StatefulKnowledgeSession newStatefulKnowledgeSession() throws Exception {
//if KnowledgeBase autowire does not works, just call directly
//KnowledgeBase kbase = readKnowledgeBase();
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
env.set( EnvironmentName.TRANSACTION_MANAGER,tm);
StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession(kbase, null, env);
return ksession;
}
}
现在,我们需要配置 spring 启动此实例以供使用:
@Autowire
private EntityManagerFactory emf;
@Autowire
private PlatformTransactionManager tm;
我们可以这样做:
//@SpringBootApplication or @Configuration
class SpringMainApplication {
//spring boo twill auto-provide a Bean of type DataSource
// if the properties are there
@Autowired
private DataSource dataSource;
@Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.acme.domain");
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
}
有很多文档和示例可以创建 EntityManagerFactory 和 TransactionManager。检查参考部分。
另外,如果你正确使用启动器,也许不需要这些配置
解决方案 3:手动创建实例
如您所见,只需要实体管理器和事务管理器。此外,要创建一个实体管理器,还需要一个有效的数据源。所以你只需要像这样的东西:
//@SpringBootApplication or @Configuration
public class SpringMainApplication{
@Bean
public KnowledgeBase readKnowledgeBase() throws Exception {
List<RuleResource> resources = new ArrayList<RuleResource>();
resources.add(new RuleResource("zzz/explore/ruleengine/rules/CalcPI.drl", ResourceType.DRL));
return KnowledgeBaseHelper.readKnowledgeBase(resources);
}
@Bean
public StatefulKnowledgeSession newStatefulKnowledgeSession() throws Exception {
//Crete datasource
//https://gist.github.com/jrichardsz/8b8dffcf1cdf42444654abc227d9f4c1
//or use the spring provided datasource
//create an entity manger
EntityManagerFactory emf = ...;
//create an transaction manger
PlatformTransactionManager tm =....;
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
env.set( EnvironmentName.TRANSACTION_MANAGER,tm);
StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession(kbase, null, env);
return ksession;
}
}
}
备注
这些片段没有经过测试,因为 drools 和数据库不容易配置,而且您没有共享最小的可运行示例。
我会加上这个研究的httplink
参考资料
- create datasource
- create datasource
- create datasource
- autowire datasource
- configure entitymanager and transaction manager
- configure entitymanager and transaction manager
- create knowledgebase
- create knowledgebase
- create knowledgebase
- JPAKnowledgeService
- JPAKnowledgeService
- JPAKnowledgeService
- JPAKnowledgeService
- JPAKnowledgeService
- JPAKnowledgeService
- spring boot starters
- spring boot starters
- StatefulKnowledgeSession
- StatefulKnowledgeSession
根据@JRichardsz 的建议,我对我的代码进行了以下更改以使其与 Spring Boot
一起使用@Autowired
private AbstractPlatformTransactionManager jtaPlatform;
@PersistenceUnit(name = "org.jbpm.persistence.jpa")
private EntityManagerFactory entityManagerFactory;
@Bean
public StatefulKnowledgeSession newStatefulKnowledgeSession() throws Exception {
RuntimeEnvironmentBuilder builder = null;
if (usePersistence) {
builder = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder()
.entityManagerFactory(entityManagerFactory)
.addEnvironmentEntry(EnvironmentName.TRANSACTION_MANAGER, jtaPlatform);
builder.knowledgeBase(readKnowledgeBase);
RuntimeManager manager = RuntimeManagerFactory.Factory.get().newSingletonRuntimeManager(builder.get());
return (StatefulKnowledgeSession) manager.getRuntimeEngine(EmptyContext.get())
.getKieSession();
}
}
对我来说 xa.properties 与 Bitronix 一起工作,但如果它不适合你那么你可以切换到 Spring 提供的数据源。