简体   繁体   中英

Bitronix + Spring + Hibernate + Persistence

I am trying to create transaction manager and use it with Hibernate for Oracle.

My persistence.xml file is:

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

In applicationContext.xml of spring I added:

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

However, when I run:

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

I get an exception:

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

The exception is on ds = (DataSource ) NamingHelper.getInitialContext(props).lookup(jndiName); of Hibernate infra file.

  1. What could be the problem?

  2. How does Hibernate persistence knows to refer to spring txManager bean?

Looks like your datasource hasn't been created yet when Persistence.createEntityManagerFactory() is called. Since your bitronixTransactionManager bean depends on the dataSource one, you should see some INFO log telling you BTM has started which should mean the datasource has been created too.

Another potential reason could be that Hibernate doesn't lookup the datasource in the right JNDI context. You could enable bitronix.tm.jndi DEBUG logs to assert that its JNDI provider is getting called.

What could be the problem?

Are you able to consume this data source in a standalone java app, by asking for jdbc/testDS1 ? In regular Tomcat DataSources, you'd need to ask for java:comp/env/jdbc/testDS1 , not only jdbc/testDS1 .

How does Hibernate persistence knows to refer to spring txManager bean?

It doesn't. You are saying this to Hibernate:

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

So, Hibernate will use the lookup class to, well, "lookup" the transaction manager :-)

Your persistence provider does its lookups on jndi. Data sources defined in Spring application context are not bound to jndi. Hence, persistence provider's lookup attempt for the data source fails as there is no such data source bound to jndi.

You may want to check http://forum.springsource.org/showthread.php?t=13984 .

Can you try defining your data sources in the server context and looking them up in your spring application by their jndi names?

Are you deploying this as a WAR or EAR? Did you declare the data source in your web.xml and set it up on the app server?

UPDATE: Since you've declared the data source in your WAR, make sure you've set up the JNDI data source in Tomcat.

Your error says: "Caused by: org.hibernate.HibernateException: Could not find datasource: jdbc/testDS1". That's a JNDI lookup name.

So where does "I don't want to" fit into this?

Spring needs a Java Naming and Directory service to look up the data source associated with this name; that's what Tomcat provides. If not Tomcat, where do you propose that Spring get it from? The naming service is part of the Java EE app server.

You either have to set up the JNDI data source and connection pool on Tomcat OR forego the benefits it provides and tell Spring to use a DriverManagerDataSource instead:

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

I believe I've got a similar scenario running. My persistence.xml is like the following:

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

And the spring application bean xml file is like:

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

Hope that helps!

I think either is the persistence.xml has not been configered correctly or you have not start up the SPring container. here I post my persistence.xml code

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>

and my testing code:

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

the transaction manager config is same as you posted. it can work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM