Bitronix + Spring + Hibernate + Persistence

Posted

技术标签:

【中文标题】Bitronix + Spring + Hibernate + Persistence【英文标题】: 【发布时间】:2011-06-28 23:47:37 【问题描述】:

我正在尝试创建事务管理器并将其与 Hibernate for Oracle 一起使用。

我的 persistence.xml 文件是:

<persistence-unit name="org.drools.persistence.jpa"
        transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>jdbc/testDS1</jta-data-source>
        <class>org.drools.persistence.session.SessionInfo</class>
        <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class>
        <class>org.drools.persistence.processinstance.WorkItemInfo</class>

        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
            <property name="hibernate.connection.autocommit" value="false" />
            <property name="hibernate.max_fetch_depth" value="3" />
            <property name="hibernate.jndi.class" value="bitronix.tm.jndi.BitronixInitialContextFactory"/> 
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.transaction.manager_lookup_class"
                value="org.hibernate.transaction.BTMTransactionManagerLookup" />
        </properties>
    </persistence-unit>

我在spring的applicationContext.xml中添加了:

<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close"> 
           <property name="className" value="oracle.jdbc.xa.client.OracleXADataSource" /> 
           <property name="uniqueName" value="jdbc/testDS1" /> 
           <property name="minPoolSize" value="1" /> 
           <property name="maxPoolSize" value="5" /> 
           <property name="driverProperties">
            <props>
                <prop key="URL">myURL</prop>
                <prop key="user">username</prop>
                <prop key="password">password</prop>
            </props>
        </property>       
    </bean> 

    <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"> 
        <property name="transactionManager" ref="bitronixTransactionManager"/> 
        <property name="userTransaction" ref="bitronixTransactionManager"/> 
    </bean> 

    <bean id="bitronixTransactionManager" factory-method="getTransactionManager" 
          class="bitronix.tm.TransactionManagerServices" depends-on="dataSource,txManager" 
          destroy-method="shutdown"/>

但是,当我运行时:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.drools.persistence.jpa");

我得到一个例外:

Caused by: org.hibernate.HibernateException: Could not find datasource: jdbc/testDS1

Hibernate infra 文件的ds = (DataSource ) NamingHelper.getInitialContext(props).lookup(jndiName); 例外。

    可能是什么问题?

    Hibernate持久化怎么知道引用springtxManagerbean?

【问题讨论】:

【参考方案1】:

调用 Persistence.createEntityManagerFactory() 时,您的数据源似乎尚未创建。由于您的 bitronixTransactionManager bean 依赖于 dataSource 之一,您应该会看到一些 INFO 日志告诉您 BTM 已启动,这应该意味着数据源也已创建。

另一个潜在的原因可能是 Hibernate 没有在正确的 JNDI 上下文中查找数据源。您可以启用 bitronix.tm.jndi 调试日志以断言其 JNDI 提供程序正在被调用。

【讨论】:

我看到它是在记录消息中创建的:2011-03-15 23:01:36,672 DEBUG (PoolingDataSource.java:84) - 为 jdbc/testDS1 构建 XA 池,有 0 个连接但我仍然得到了例外! 再次:另一个潜在的原因可能是 Hibernate 没有在正确的 JNDI 上下文中查找数据源。您可以启用 bitronix.tm.jndi 调试日志以断言其 JNDI 提供程序正在被调用。【参考方案2】:

可能是什么问题?

您能否通过请求jdbc/testDS1 在独立的Java 应用程序中使用此数据源?在常规的 Tomcat 数据源中,您需要询问 java:comp/env/jdbc/testDS1,而不仅仅是 jdbc/testDS1

Hibernate 持久化如何知道引用 spring txManager bean?

它没有。你对 Hibernate 这么说:

        <property name="hibernate.transaction.manager_lookup_class"
            value="org.hibernate.transaction.BTMTransactionManagerLookup" />

因此,Hibernate 将使用查找类来“查找”事务管理器 :-)

【讨论】:

嗨!我刚刚意识到我的问题是我需要在上下文中找到 java:comp/UserTransaction。问题不在于 ds1。当我使用 tomcat 创建它时,它会自动将 选项卡绑定到 java:comp/UserTransaction。我怎样才能用 Spring 做到这一点?【参考方案3】:

您的持久性提供程序在 jndi 上进行查找。 Spring 应用程序上下文中定义的数据源不绑定到 jndi。因此,持久性提供程序对数据源的查找尝试失败,因为没有此类数据源绑定到 jndi。

您可能需要查看http://forum.springsource.org/showthread.php?t=13984。

您可以尝试在服务器上下文中定义您的数据源并在您的 Spring 应用程序中通过它们的 jndi 名称来查找它们吗?

【讨论】:

【参考方案4】:

您是将其部署为 WAR 还是 EAR?您是否在 web.xml 中声明了数据源并在应用服务器上进行了设置?

更新:由于您已在 WAR 中声明数据源,因此请确保您已在 Tomcat 中 set up JNDI 数据源。

您的错误说:“由:org.hibernate.HibernateException:找不到数据源:jdbc/testDS1”。这是一个 JNDI 查找名称。

那么“我不想”在哪里适合呢?

Spring 需要一个 Java 命名和目录服务来查找与该名称关联的数据源;这就是Tomcat提供的。如果不是 Tomcat,你建议 Spring 从哪里获取它?命名服务是 Java EE 应用服务器的一部分。

您要么必须在 Tomcat 上设置 JNDI 数据源和连接池,要么放弃它提供的好处并告诉 Spring 改用 DriverManagerDataSource:

http://static.springsource.org/spring/docs/2.5.x/reference/jdbc.html

【讨论】:

如果我使用 Spring,为什么需要使用 tomcat 设置 JNDI 数据? 其实这对我有用。不起作用的是:DataSource ds = (DataSource) ic.lookup("java:comp/UserTransaction");当我用tomcat配置它时,它曾经工作过。我也不直接使用spring 所以在您的回答中,您实际上是在说我必须同时配置 tomcat 和 spring 才能获得“java:comp/UserTransaction”jndi? 恐怕 Spring 文档会说其他内容

对于典型的 JTA 事务(必需、支持、强制、从不),您只需要一个简单的 JtaTransactionManager 定义,完全可移植J2EE 服务器。这对应于 JTA UserTransaction 的功能,J2EE 为其指定标准 JNDI 名称(“java:comp/UserTransaction”)。无需为这种 79 * 种 JTA 用法配置特定于服务器的 TransactionManager 查找。阅读更多:kickjava.com/src/org/springframework/transaction/jta/…

【参考方案5】:

我相信我正在运行类似的场景。我的 persistence.xml 如下:

<persistence-unit name="myPersistenceUnit" transaction-type="RESOURCE_LOCAL">
    <!-- other configuration ommited -->
    <jta-data-source>java:comp/env/jdbc/YourPersistentUnitJNDI_Name</jta-data-source>
    <!-- other configuration ommited -->
</persistence-unit>

而spring应用bean xml文件是这样的:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="myPersistenceUnit" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
        </bean>

希望有帮助!

【讨论】:

【参考方案6】:

我认为要么是persistence.xml 没有正确配置,要么你没有启动SPring 容器。 在这里我发布我的 persistence.xml 代码

enter code here
<persistence-unit name="org.drools.task" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/mysql</jta-data-source>
    <class>org.drools.task.Attachment</class>
<properties>
        <property name="hibernate.archive.autodetection" value="class"/>
        <property name="hibernate.current_session_context_class" value="jta" />
        <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup" />
        <property name="hibernate.jndi.class" value="bitronix.tm.jndi.BitronixInitialContextFactory"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
        <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
        <property name="hibernate.show_sql" value="true" />

        <!-- after first run the application, should comment it, else it will drop and create table each time 
        <property name="hibernate.hbm2ddl.auto" value="create" /> -->
</properties>
</persistence-unit>

和我的测试代码:

enter code here
    ApplicationContext ctx = new FileSystemXmlApplicationContext("applicationContext.xml");
    JtaTransactionManager txManager = (JtaTransactionManager) ctx.getBean("txManager");
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    TransactionStatus status = txManager.getTransaction(def);
    System.out.println("The transaction manager is "+txManager);
    System.out.println("The transaction is "+status);

事务管理器配置与您发布的相同。 它可以工作。

【讨论】:

以上是关于Bitronix + Spring + Hibernate + Persistence的主要内容,如果未能解决你的问题,请参考以下文章

hiber

Hibernate + spring 版本兼容性

SSH整合

PostgreSQL springboot spring data jpa 集成

如何解决“引起:java.lang.IllegalStateException:文件被锁定:nio:/Development/hiber/data/contactmgr.mv.db [1.4.192/

Spring Boot : Mybatis极简配置