Announcement Announcement Module
Collapse
No announcement yet.
Hibernate not inserting/comitting but OpenJpa does Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hibernate not inserting/comitting but OpenJpa does

    Hello all,

    I have a small issue. Unfortunately this one is quite complicated and only someone that has had this before will spot the problem. I wasn't sure where to go with this one, I have posted somthing similar thread on the Hibernate forum but I am guessing that someone here could also have had this in the past.

    Well, I have wired an application with Spring. There is a datasource and an entity manager that are configured together. So far so good. However to play nicely together the transaction manager hierarchy is as follows:

    Bitronix
    Spring JTA
    Spring JPA

    Here are the pertinent configurations (sorry about the length, included all just for completeness). The only interesting parts I think are the jpaPropertyMap in the Spring config, and the persist method in the class.

    Spring:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    	<context:property-placeholder 
    		location="classpath:/META-INF/spring-test.properties"  />
    		
    	<!-- Bean post-processor for JPA annotations. -->
    	<context:annotation-config />
    	
    	<!-- The transaction manager services. -->
    	<bean 
    		id="bitronix.tm.TransactionManagerServices"
    		class="bitronix.tm.TransactionManagerServices"
    		factory-method="getConfiguration"
    		destroy-method="shutdown">
    		<property name="serverId" value="spring-btm" />
    		<property name="disableJmx" value="false" />
    	</bean>
    
    	<!-- The transaction manager. -->
    	<bean 
    		id="bitronix.tm.BitronixTransactionManager"
    		depends-on="bitronix.tm.TransactionManagerServices"
    		class="bitronix.tm.TransactionManagerServices"
    		factory-method="getTransactionManager"
    		destroy-method="shutdown"
    		p:transactionTimeout="600000">
    	</bean>
    
    	<!-- The Spring transaction manager. -->
    	<bean 
    		id="org.springframework.transaction.jta.JtaTransactionManager"
    		class="org.springframework.transaction.jta.JtaTransactionManager"
    		p:userTransaction-ref="bitronix.tm.BitronixTransactionManager"
    		p:transactionManager-ref="bitronix.tm.BitronixTransactionManager"
    		p:allowCustomIsolationLevels="true">
    	</bean>
    	
    	<!-- 
    		The Spring JPA transaction manager.
    		name="transactionManager" 
    	-->
    	<bean
    		id="org.springframework.orm.jpa.JpaTransactionManager"
    		class="org.springframework.orm.jpa.JpaTransactionManager"
    		p:entityManagerFactory-ref="entityManagerFactory" />
    
    	<!-- For multiple persistence units we need this manager. -->
    	<bean 
    		id="persistenceUnitManager" 
    		class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"
    		p:defaultDataSource-ref="orbisDataSource"
    		p:persistenceXmlLocations="${persistence-test.xml}">
    	</bean>
    	
    	<!-- 
    		This factory is for the entity managers. Entity manager factories are heavy and entity managers are light.
    		OpenJpaVendorAdapter, HibernateJpaVendorAdapter 
    	-->
    	<bean id="entityManagerFactory"
    			class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    			p:jpaVendorAdapter-ref="jpaVendorAdapter"
    			p:jpaPropertyMap-ref="jpaPropertyMap"
    			p:persistenceUnitManager-ref="persistenceUnitManager">
    	</bean>
    	<util:map id="jpaPropertyMap">
    		<entry key="openjpa.TransactionMode" value="managed" />
    		<entry key="openjpa.ConnectionFactoryMode" value="managed" />
    		<entry key="openjpa.ManagedRuntime" value="invocation(TransactionManagerMethod=bitronix.tm.TransactionManagerServices.getTransactionManager)" />
    		<entry key="openjpa.ConnectionFactoryProperties" value="PrettyPrint=true,PrettyPrintLineLength=150" />
    		<entry key="openjpa.Log" value="DefaultLevel=TRACE,SQL=TRACE,File=openjpa.log,Runtime=TRACE,Tool=TRACE" />
    		<entry key="openjpa.QueryCache" value="true(CacheSize=10000,SoftReferenceSize=1000)" />
    		<entry key="openjpa.LockTimeout" value="600000" />
    		<entry key="openjpa.Connection2UserName" value="${jdbc.user}" />
    		<entry key="openjpa.Connection2Password" value="${jdbc.password}" />
    		<entry key="openjpa.Connection2URL" value="${jdbc.url}" />
    		<entry key="openjpa.Connection2DriverName" value="${jdbc.driver}" />
    		<entry key="openjpa.ConnectionUserName" value="${jdbc.user}" />
    		<entry key="openjpa.ConnectionPassword" value="${jdbc.password}" />
    		<entry key="openjpa.ConnectionURL" value="${jdbc.url}" />
    		<entry key="openjpa.ConnectionDriverName" value="${jdbc.driver}" />
    	
    		<entry key="hibernate.connection.username" value="${jdbc.user}" />
    		<entry key="hibernate.connection.password" value="${jdbc.password}" />
    		<entry key="hibernate.dialect" value="${jdbc.dialect}" />
    		<entry key="hibernate.connection.url" value="${jdbc.url}" />
    		<entry key="hibernate.connection.driver_class" value="${jdbc.driver}" />
    		<entry key="hibernate.query.factory_class" value="org.hibernate.hql.ast.ASTQueryTranslatorFactory" />
    		<entry key="hibernate.hbm2ddl.auto" value="none" />
    		<entry key="hibernate.show_sql" value="true" />
    		<entry key="hibernate.format_sql" value="false" />
    		<entry key="hibernate.cache.use_second_level_cache" value="false" />
    		<entry key="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup" />
    		<!--<entry key="hibernate.current_session_context_class" value="resourceLocal" />-->
    		<!--<entry key="transaction.factory.class" value="org.hibernate.transaction.JTATransactionFactory" />-->
    	</util:map>
    	
    	<!-- OpenJpaVendorAdapter, HibernateJpaVendorAdapter -->
    	<bean id="jpaVendorAdapter"
    		class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"  />
    	
    	<!-- This is the datasource that will be used by the application it's self.Typically this datasource should be transactional. -->
    	<bean id="orbisDataSource"
    		class="bitronix.tm.resource.jdbc.PoolingDataSource"
    		init-method="init"
    		destroy-method="close"
    		p:className="${jdbc.dataSource}"
    		p:uniqueName="${jdbc.dataSource}"
    		p:minPoolSize="${jdbc.min.pool.size}"
    		p:maxPoolSize="${jdbc.max.pool.size}"
    		p:allowLocalTransactions="false"
    		p:automaticEnlistingEnabled="false"
    		p:useTmJoin="true"
    		p:driverProperties-ref="driverProperties">
    	</bean>
    	<util:properties id="driverProperties">
    		<prop key="URL">${jdbc.url}</prop>
    		<prop key="user">${jdbc.user}</prop>
    		<prop key="password">${jdbc.password}</prop>
    	</util:properties>
    	
    	<bean 
    		id="com.agfa.spring.persistence.DataBaseJpa"
    		name="com.agfa.spring.persistence.DataBaseJpa" 
    		class="com.agfa.spring.persistence.DataBaseJpa"  />
    		
    	<!-- The transaction advice is necessary for the transaction handler. -->
    	<tx:advice id="org.springframework.aop.BeforeAdvice"
    		transaction-manager="org.springframework.transaction.jta.JtaTransactionManager">
    		<tx:attributes>
    			<tx:method name="*" propagation="REQUIRED" />
    		</tx:attributes>
    	</tx:advice>
    	<aop:config proxy-target-class="true">
    		<aop:pointcut id="com.agfa.spring.persistence.DataBaseJpa.Pointcut" expression="execution(* com.agfa.spring.persistence.DataBaseJpa.*(..))" />
    		<aop:advisor advice-ref="org.springframework.aop.BeforeAdvice" pointcut-ref="com.agfa.spring.persistence.DataBaseJpa.Pointcut" />
    	</aop:config>
    	
    </beans>
    Persistence:
    Code:
    <?xml version="1.0"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="
    		http://java.sun.com/xml/ns/persistence
        	http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
    	<persistence-unit name="ServiceBeanUnit" transaction-type="RESOURCE_LOCAL">
    		<!-- 
    			org.hibernate.ejb.HibernatePersistence,
    			org.apache.openjpa.persistence.PersistenceProviderImpl
    		-->
    		<provider>org.hibernate.ejb.HibernatePersistence</provider>
    		<class>com.agfa.spring.bean.PdfDocument</class>
    		<exclude-unlisted-classes>false</exclude-unlisted-classes>
    
    	</persistence-unit>
    </persistence>
    And the class for persistence:
    Code:
    package com.agfa.spring.persistence;
    
    /**
     * This bean is for accessing the database with JPA.
     * 
     * @author axhup
     * @since 28.04.10
     * @version 01.00
     */
    @Local(value = { DataBase.class })
    @Remote(value = { IDataBase.class })
    @Stateless(mappedName = DataBaseJpa.JNDI_NAME)
    public class DataBaseJpa implements DataBase, IDataBase {
    
    	public static final String JNDI_NAME = "DataBaseJpa/remote";
    
    	/** The logger for the bean. */
    	private Logger logger = Logger.getLogger(DataBaseJpa.class);
    	/** Entity manager for the bean will be injected. */
    	@PersistenceContext(type = PersistenceContextType.TRANSACTION, unitName = IConstants.PSERSISTENCE_UNIT)
    	protected EntityManager entityManager;
    
    	/**
    	 * {@inheritDoc}
    	 */
    	public <T> T persist(T object) {
    		if (object != null) {
    			entityManager.persist(object);
    		}
    		return object;
    	}
    
    }
    Now on the grounds that this configuration works with OpenJpa I have to assume that there is somthing that I am missing from the Hibernate configuration. However I don't see any warnings from Bitronix saying that there are no resources in the transaction. I also specified that Hibernate print the SQL, but I see no insert statement, I do see a select though, and an access to the sequence table, which is duly incremented. This is in a unit test environment, as an aside.

    I can't think of anything that could be helpfull. I thank you for reading this far, and for the attention.

    Thanks in advance for any thoughts.

    Regards,
    Michael

  • #2
    Michael,
    I had a problem with Bitronix and Hibernate where even though FlushMode was set to COMMIT no flush was taking place. Not sure that this is your problem as well but sounds like it.
    I added an advice around my transactional service to manually flush the transaction as an interim solution and am still looking for the reason why this was happening. To test whether this is the same problem just grab a hold of the session and call flush() on it before you exit your transactional method and see if that fixes your problem.

    Comment


    • #3
      Hibernate not inserting/comitting but OpenJpa does

      Hi Bd,

      Thanks for the reply! Appreciated, not an easy one to look at. However I don't come empty handed, I found the solution, with a little help from one of the Hibernate chaps. He suggested that the transaction-type in the persistence.xml should be JTA and I had RESOURCE_LOCAL. Which I duly changed, and the result was the same, no insert or commit, and no insert SQL from Hibernate either. Then I noticed that Bitronix complained about overiding the 'hibernate.transaction.factory_class' in the entity manager configuration. So I commented this out, and violla, all was rosy!

      So just for completeness here is the final working solution.

      Code:
      <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      	xsi:schemaLocation="
      		http://java.sun.com/xml/ns/persistence
          	http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
      	<persistence-unit name="ServiceBeanUnit" transaction-type="JTA">
      		<!-- 
      			org.hibernate.ejb.HibernatePersistence,
      			org.apache.openjpa.persistence.PersistenceProviderImpl
      		-->
      		<provider>org.hibernate.ejb.HibernatePersistence</provider>
      		<class>com.agfa.spring.bean.PdfDocument</class>
      		<exclude-unlisted-classes>false</exclude-unlisted-classes>
      
      	</persistence-unit>
      </persistence>
      Code:
      	<context:property-placeholder 
      		location="classpath:/META-INF/spring-test.properties"  />
      		
      	<!-- Bean post-processor for JPA annotations. -->
      	<context:annotation-config />
      	
      	<!-- The transaction manager services. -->
      	<bean 
      		id="bitronix.tm.TransactionManagerServices"
      		class="bitronix.tm.TransactionManagerServices"
      		factory-method="getConfiguration"
      		destroy-method="shutdown">
      		<property name="serverId" value="spring-btm" />
      		<property name="disableJmx" value="false" />
      	</bean>
      
      	<!-- The transaction manager. -->
      	<bean 
      		id="bitronix.tm.BitronixTransactionManager"
      		depends-on="bitronix.tm.TransactionManagerServices"
      		class="bitronix.tm.TransactionManagerServices"
      		factory-method="getTransactionManager"
      		destroy-method="shutdown"
      		p:transactionTimeout="600000">
      	</bean>
      
      	<!-- The Spring transaction manager. -->
      	<bean 
      		id="org.springframework.transaction.jta.JtaTransactionManager"
      		class="org.springframework.transaction.jta.JtaTransactionManager"
      		p:userTransaction-ref="bitronix.tm.BitronixTransactionManager"
      		p:transactionManager-ref="bitronix.tm.BitronixTransactionManager"
      		p:allowCustomIsolationLevels="true">
      	</bean>
      	
      	<!-- 
      		The Spring JPA transaction manager.
      		name="transactionManager" 
      	-->
      	<bean
      		id="org.springframework.orm.jpa.JpaTransactionManager"
      		class="org.springframework.orm.jpa.JpaTransactionManager"
      		p:entityManagerFactory-ref="entityManagerFactory" />
      
      	<!-- For multiple persistence units we need this manager. -->
      	<bean 
      		id="persistenceUnitManager" 
      		class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"
      		p:defaultDataSource-ref="orbisDataSource"
      		p:persistenceXmlLocations="${persistence-test.xml}">
      	</bean>
      	
      	<!-- 
      		This factory is for the entity managers. Entity manager factories are heavy and entity managers are light.
      		OpenJpaVendorAdapter, HibernateJpaVendorAdapter 
      	-->
      	<bean id="entityManagerFactory"
      			class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
      			p:jpaVendorAdapter-ref="jpaVendorAdapter"
      			p:jpaPropertyMap-ref="jpaPropertyMap"
      			p:persistenceUnitManager-ref="persistenceUnitManager">
      	</bean>
      	<util:map id="jpaPropertyMap">
      		<entry key="openjpa.TransactionMode" value="managed" />
      		<entry key="openjpa.ConnectionFactoryMode" value="managed" />
      		<entry key="openjpa.ManagedRuntime" value="invocation(TransactionManagerMethod=bitronix.tm.TransactionManagerServices.getTransactionManager)" />
      		<entry key="openjpa.ConnectionFactoryProperties" value="PrettyPrint=true,PrettyPrintLineLength=150" />
      		<entry key="openjpa.Log" value="DefaultLevel=TRACE,SQL=TRACE,File=openjpa.log,Runtime=TRACE,Tool=TRACE" />
      		<entry key="openjpa.QueryCache" value="true(CacheSize=10000,SoftReferenceSize=1000)" />
      		<entry key="openjpa.LockTimeout" value="600000" />
      		<entry key="openjpa.Connection2UserName" value="${jdbc.user}" />
      		<entry key="openjpa.Connection2Password" value="${jdbc.password}" />
      		<entry key="openjpa.Connection2URL" value="${jdbc.url}" />
      		<entry key="openjpa.Connection2DriverName" value="${jdbc.driver}" />
      		<entry key="openjpa.ConnectionUserName" value="${jdbc.user}" />
      		<entry key="openjpa.ConnectionPassword" value="${jdbc.password}" />
      		<entry key="openjpa.ConnectionURL" value="${jdbc.url}" />
      		<entry key="openjpa.ConnectionDriverName" value="${jdbc.driver}" />
      	
      		<entry key="hibernate.connection.username" value="${jdbc.user}" />
      		<entry key="hibernate.connection.password" value="${jdbc.password}" />
      		<entry key="hibernate.dialect" value="${jdbc.dialect}" />
      		<entry key="hibernate.connection.url" value="${jdbc.url}" />
      		<entry key="hibernate.connection.driver_class" value="${jdbc.driver}" />
      		<entry key="hibernate.query.factory_class" value="org.hibernate.hql.ast.ASTQueryTranslatorFactory" />
      		<entry key="hibernate.hbm2ddl.auto" value="none" />
      		<entry key="hibernate.show_sql" value="true" />
      		<entry key="hibernate.format_sql" value="false" />
      		<entry key="hibernate.cache.use_second_level_cache" value="false" />
      		
      		<!--<entry key="hibernate.current_session_context_class" value="org.hibernate.context.JTASessionContext" />-->
      		<!--<entry key="hibernate.connection.release_mode" value="after_statement" />-->
      		<!--<entry key="hibernate.transaction.flush_before_completion" value="true" />-->
      		<!--<entry key="hibernate.transaction.auto_close_session" value="false" />-->
      		<!--<entry key="TransactionStrategy" value="org.hibernate.transaction.JTATransactionFactory" />-->
      		<!--<entry key="hibernate.current_session_context_class" value="thread" />-->
      		<!--<entry key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />-->
      		<entry key="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup" />
      	</util:map>
      	
      	<!-- OpenJpaVendorAdapter, HibernateJpaVendorAdapter -->
      	<bean id="jpaVendorAdapter"
      		class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"  />
      	
      	<!-- This is the datasource that will be used by the application it's self.Typically this datasource should be transactional. -->
      	<bean id="orbisDataSource"
      		class="bitronix.tm.resource.jdbc.PoolingDataSource"
      		init-method="init"
      		destroy-method="close"
      		p:className="${jdbc.dataSource}"
      		p:uniqueName="${jdbc.dataSource}"
      		p:minPoolSize="${jdbc.min.pool.size}"
      		p:maxPoolSize="${jdbc.max.pool.size}"
      		p:allowLocalTransactions="false"
      		p:automaticEnlistingEnabled="false"
      		p:useTmJoin="true"
      		p:driverProperties-ref="driverProperties">
      	</bean>
      	<util:properties id="driverProperties">
      		<prop key="URL">${jdbc.url}</prop>
      		<prop key="user">${jdbc.user}</prop>
      		<prop key="password">${jdbc.password}</prop>
      	</util:properties>
      	
      	<bean 
      		id="com.agfa.spring.persistence.DataBaseJpa"
      		name="com.agfa.spring.persistence.DataBaseJpa" 
      		class="com.agfa.spring.persistence.DataBaseJpa"  />
      		
      	<!-- The transaction advice is necessary for the transaction handler. -->
      	<tx:advice id="org.springframework.aop.BeforeAdvice"
      		transaction-manager="org.springframework.transaction.jta.JtaTransactionManager">
      		<tx:attributes>
      			<tx:method name="*" propagation="REQUIRED" />
      		</tx:attributes>
      	</tx:advice>
      	<aop:config proxy-target-class="true">
      		<aop:pointcut id="com.agfa.spring.persistence.DataBaseJpa.Pointcut" expression="execution(* com.agfa.spring.persistence.DataBaseJpa.*(..))" />
      		<aop:advisor advice-ref="org.springframework.aop.BeforeAdvice" pointcut-ref="com.agfa.spring.persistence.DataBaseJpa.Pointcut" />
      	</aop:config>
      Code:
      /**
       * This bean is for accessing the database with JPA.
       * 
       * @author axhup
       * @since 28.04.10
       * @version 01.00
       */
      @Local(value = { DataBase.class })
      @Remote(value = { IDataBase.class })
      @Stateless(mappedName = DataBaseJpa.JNDI_NAME)
      public class DataBaseJpa implements DataBase, IDataBase {
      
      	public static final String JNDI_NAME = "DataBaseJpa/remote";
      
      	/** The logger for the bean. */
      	private Logger logger = Logger.getLogger(DataBaseJpa.class);
      	/** Entity manager for the bean will be injected. */
      	@PersistenceContext(type = PersistenceContextType.TRANSACTION, unitName = IConstants.PSERSISTENCE_UNIT)
      	protected EntityManager entityManager;
      
      
      	/**
      	 * {@inheritDoc}
      	 */
      	public <T> T persist(T object) {
      		if (object != null) {
      			entityManager.persist(object);
      		}
      		return object;
      	}
      
      
      }
      Good luck,
      Michael

      Comment

      Working...
      X