【问题标题】:Unable to lookup JNDI name [jdbc/jbpm-ds]无法查找 JNDI 名称 [jdbc/jbpm-ds]
【发布时间】:2020-05-11 20:44:02
【问题描述】:

我正在尝试开发 jBPM spring boot 应用程序,但出现 Unable to lookup JNDI name [jdbc/jbpm-ds] 错误。

为此,我使用了 jbpm-7.36.0.Final、Spring-Boot-2.2.6 和 jbpm-spring-boot 7.36.0 Final 以及 spring boot 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

下面是代码sn-p

    @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

我也很想知道我的以下理解是否正确

  1. jBPM 仅支持 JTA 类型的事务,即全局事务。集成 jBPM 时不能使用 RESOURCE_LOCAL 事务类型。
  2. 当我说事务类型 RESOURCE_LOCAL 时,意味着只有一个数据源事务将在应用程序之间共享。
  3. jBPM RuntimeManager 使用“org.jbpm.domain”持久化单元名称(强制类型)来处理它的所有内部表操作。
  4. 所有特定于应用程序的事务都可以通过默认的持久性单元名称来处理,即'org.jbpm.persistence.jpa'。这可以被自定义持久性上下文覆盖。
  5. JTA进一步分为XADatasource类型和Non-XADatasource类型两种。当数据源位于应用服务器容器中时,应使用 XADatasource。 Non-XADatasource 对于基于 EJB 的应用程序很有用。
  6. 配置下需要XADatasource

    &lt;provider&gt;org.hibernate.jpa.HibernatePersistenceProvider&lt;/provider&gt;

    <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" />

  7. 配置下需要非XADatasource

    &lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;

    &lt;property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/&gt;

  8. 第 6 点或第 7 点是否必要,如果需要,如何不使用 persistence.xml。

  9. 下面的属性有什么用,什么jar有这个类

    spring.jpa.properties.hibernate.transaction.manager_lookup_class=org.hibernate.transaction.BTMTransactionManagerLookup

【问题讨论】:

  • 从属性中删除 .xa。最近我正在尝试对 Hikari 做同样的事情检查我的主题stackoverflow.com/questions/61735853/…
  • 嗨@Evgeniy,我从数据源配置中删除了 .xa.properties 并重新运行我的应用程序,但面临同样的问题。我认为 bitronix 事务管理器是 XADatasource 类型而不是 Non-XADatasource 类型。因此,对于 XADatasource,它会尝试从 JNDI 名称“jdbc/jbpm-ds”中获取数据源连接。但是,如果我告诉 bitronix TXM 使用非 XADatasource,那么它可能会从 application.properties 中查找 Datasource 连接并可能会解决我的问题。
  • 看来您需要在 context.xml too 中定义该数据源。 jBPM 很可能试图通过容器而不是通过 spring 来识别数据源(换句话说,容器不知道您在应用程序中有数据源)。另一个看似有用的链接:persistence JBPM5.3 on tomcat with mysql
  • @m4gic 是的,显然你是对的。我也想过,但确实是大错特错。因为我可以清楚地看到如果我在应用程序级别配置数据源,jBPM 能够删除/创建内部表,但是当涉及到自定义表或数据库连接时,它正在寻找服务器级别的数据源。无论如何,我非常感谢您的建议和您分享的链接。参考源真的很有用,我一定会尝试,如果它有效,请告诉你。

标签: java spring-boot jta bitronix redhat-bpm


【解决方案1】:

有一些误解:

  • jbpm-spring-boot-starter-basic 正在使用,但是您没有使用任何弹簧加载的 bean 来创建 StatefulKnowledgeSession。 starter 的主要思想是避免低级别的框架配置。
  • 这个参数:spring.datasource.xa.properties.uniqueName没有出现在文档中,是camelCase。

解决方案 1:弹簧启动

使用正式版及其配置

#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 数据源引擎,没有任何 数据库配置.为什么?因为 StatefulKnowledgeSession 只需要一个经典的数据库连接。

也许这个启动器初始化了一个 StatefulKnowledgeSession 准备在任何带有 @Autowire

的 Spring Java bean 中使用

方案二:Spring + 手动配置

一项简单的研究告诉我,从 JPAKnowledgeService 创建 StatefulKnowledgeSession 需要经典:

EntityManagerFactory 和 TransactionManager

这也可以在您的代码中看到:

Environment env = EnvironmentFactory.newEnvironment();
            env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, entityManagerFactory);
            env.set(EnvironmentName.TRANSACTION_MANAGER, tm);

在这个例子中:

http://www.javased.com/index.php?source_dir=droolsjbpm-integration/drools-container/drools-spring/src/main/java/org/drools/container/spring/beans/StatefulKnowledgeSessionBeanFactory.java

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() );

所以解决方案可能只是配置一个弹簧靴来拥有优雅的自动装配:

//@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 boot 这个实例以供使用:

@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:手动创建实例

如您所见,只需要 entitymanager 和 transactionmanager。此外,要创建实体管理器,还需要有效的数据源。所以你只需要这样的东西:

//@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;
  }

}

}

注意

  • 这些 sn-ps 没有经过测试,因为 drools 和数据库不容易配置,而且您没有共享最小的可运行示例。

  • 我会添加这个研究的http链接

参考文献

【讨论】:

  • 嗨@JRichardsz,我接受了你的建议并选择了解决方案1,因为这正是我想要的。您提到Maybe this starter initialize a StatefulKnowledgeSession ready to use in any spring java bean with an @Autowire 的那一行给了我一个提示。所以尝试@Autowire AbstractPlatformTransactionManager 并从@PersistenceUnit 获得EntityManagerFactory。发布整个代码作为答案。
【解决方案2】:

根据@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 提供的数据源。

【讨论】:

  • @pafau k。 ans之间有很大的区别。和提示。希望你能理解。
猜你喜欢
  • 1970-01-01
  • 2016-04-09
  • 1970-01-01
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
  • 1970-01-01
  • 2014-11-09
  • 1970-01-01
相关资源
最近更新 更多