Announcement Announcement Module
Collapse
No announcement yet.
Spring Hibernate declarative transaction management issue - rollback does not work Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring Hibernate declarative transaction management issue - rollback does not work

    I am having trouble with rolling back transaction, I am using declarative transaction management using Spring (2.5.x) and Hibernate (3.2.x). My DAO class has the @Transactional annotation and I inject the SessionFactory in it. But when I call getCurrentSession method on it, I get a Hibernate session instead of Spring session. So looks like the LocalSessionFactoryBean is not being injected correctly and Spring is not aware of Hibernate's session. If I switch to programmatic transaction management, I am able to rollback transactions.

    Code:
        <bean id="custAccountSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <property name="dataSource" ref="dataSourceDB2JNDICustAcct"/>
            <property name="mappingResources">
                <list>
                        <!-- hbm xml mapping stuff -->
                </list>
            </property>
            <property name="hibernateProperties">
    	        <props>
    	            <prop key="hibernate.dialect">org.hibernate.dialect.DB2390Dialect</prop>
    	            <prop key="hibernate.cache.use_second_level_cache">false</prop>
    	            <prop key="hibernate.connection.autocommit">false</prop>
    	        </props>
            </property>
        </bean>
        
        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory"><ref local="custAccountSessionFactory"/></property>
        </bean>
    	
    	<tx:annotation-driven transaction-manager="transactionManager"/>
    	
        <bean id="custAcctTransactionManager" class="com.customer.orch.CustomerAccountTransactionManager">
        	<property name="sessionFactory"><ref local="custAccountSessionFactory"/></property>
        </bean>
    I have an interface which I implement in the following class
    Code:
    public class CustomerAccountTransactionManager implements ICustomerAccountTransactionManager {
    
    	private SessionFactory sessionFactory;
    	public void setSessionFactory(SessionFactory sessionFactory) {
    		this.sessionFactory = sessionFactory;
    	}
    
    	@Override
    	@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED, rollbackFor=Exception.class)	
    	public void persist(String policyNumber, PersonInfo person, String shadowId, 
    			String systemOfOrigin, String activityType, String guid) throws Exception {
    		Session session = sessionFactory.getCurrentSession();
    		//session.beginTransaction();
    		try {
    			session.saveOrUpdate(custAccountInfo);
    			//session.getTransaction().commit();
    		} catch(RuntimeException re) {
    			//session.getTransaction().rollback();
    			LOGGER.error("Error adding alert preferences: ",re);
    			throw re;
    		}
    
    	}
    }
    On session.saveOrUpdate(custAccountInfo), if a SQL exception is thrown, I can see in the console that Spring is trying to rollback the transaction. But I can see partial inserts in the database. I am using DB2 database.

    I should add the class that calls CustomerAccountTransactionManager is defined in a different content xml which imports the one above. The parent spring context also defines a BeanFactory. I am not sure if that will impact Spring's transaction handling.

    When an exception is throw, I can see in the console that Spring trying to rollback the transaction -

    Initiating transaction rollback
    Rolling back JDBC transaction on Connection [org.jboss.resource.adapter.jdbc.WrappedConnection@ 594b86d]
    Closing Hibernate Session
    releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
    transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
    Resetting isolation level of JDBC Connection [org.jboss.resource.adapter.jdbc.WrappedConnection@ 594b86d] to 2
    Releasing JDBC Connection [org.jboss.resource.adapter.jdbc.WrappedConnection@ 594b86d] after transaction
    Returning JDBC Connection to DataSource

    The exception that's thrown is

    Code:
    org.hibernate.PropertyValueException: not-null property references a null or transient value: com.sentry.nsa.customer.dao.dataobjects.VktCustAccntPolicy.capPolicyNum
    	at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
    	at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:290)
    	at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
    Last edited by santosh911; Mar 27th, 2012, 05:05 PM. Reason: fixed syntax

  • #2
    There is no spring session so not sure where you get/got that from.

    If your rollback isn't working it in general means you have a setup wrong on the other hand if getCUrrentSession works it means that there is a transaction in progress, else you would get an exception.

    So please post your configuration and setup and not just the parts here.

    On a final note your transactions should be actually defined on the service layer as that is your transactional boundary (you want that method to either fully fail or succeed not only a single dao call!).

    Comment


    • #3
      My understanding was that the call to getCurrentSession would return a Spring proxy of hibernate session and not hibernate's SessionImpl itself. Doesn't look like that's the case.

      Anyway, looks like the issue is that I have multiple transaction managers. I have a hibernate transaction manager and also DataSourceTransactionManager and looks like @Transactional is injecting DataSourceTransactionManager where I would have expected HibernateTransactionManager. I am going to try using aop to inject the correct transaction manager and get rid of @Transactional annotation. If you have a better suggestion please let me know. I appreciate your time/response.

      Comment


      • #4
        My understanding was that the call to getCurrentSession would return a Spring proxy of hibernate session and not hibernate's SessionImpl itself. Doesn't look like that's the case.
        No it doesn't return a proxy it returns a hibernate session nothing more nothing less.

        Don't use multiple tx managers. Why do you need multiple? Simply use the HibernateTransactionmanager that is also perfectly capably ofm anaging JDBC transactions.

        Comment


        • #5
          Well, we are moving from iBatis to Hibernate, the old transaction managers support iBatis transactions. I am not sure if I want to change any of that since it is already in production. AOP obviously does not let me specify transaction attributes for my service methods so I used Spring's TransactionProxyFactoryBean. Thanks for your assistance Marten!

          Comment


          • #6
            As I stated the HibernateTransactionManager is perfectly capable of managing plain JDBC transactions. Instead of trying to hack your way into (or out of) it simply remove the DatasourceTransactionManager. Everything will still work without an extra layer of configuration (I consider the TransactionProxyFactoryBean deprecated) or an extra layer of complexity.

            Comment

            Working...
            X