hibernate transaction not rolling back correctly

19,321

Transactions don't "cascade". At the JDBC level, a transaction consists of:

  1. Turning off autocommit
  2. Executing some statements
  3. Calling java.sql.Connection.commit() or java.sql.Connection.rollback().

If you're saying that some things are being committed and some are rolled back, then there's something wrong in your transaction management. Either autocommit is on or you actually have multiple calls to commit() happening.

Share:
19,321
PPP
Author by

PPP

Updated on June 09, 2022

Comments

  • PPP
    PPP almost 2 years

    I have 2 tables, say Item and Property and a hibernate object mapped to both. The mapping for table Item to Property looks like

    <set name="propertySet" cascade="all-delete-orphan">
        <key column="item_id" not-null="true"/>
        <one-to-many class="Property"/>
    </set>
    

    An item can have multiple properties. Everything like select, insert works properly. but when there is an error, the inserts to the property table do not rollback.

    What happens is that if i am editing an item with N properties and enter an invalid value in a field, the next time I retrieve the item, it has 2*N properties.

    Edit ---

    What my class looks like is

    @Autowired
    SessionFactory sessionFactory
    
    @Transactional
    public void updateItem(Item i){
        ...
        // The only 2 statements dealing with hibernate or session in this function
        ItemModel im = sessionFactory.getCurrentSession().get(...);
    
        sessionFactory.getCurrentSession().update(updatedItem);
        ...
    }
    

    I am using annotated transactions (@Transactional) with the spring framework and the lowest exception getting thrown is

    Caused by: org.springframework.transaction.TransactionSystemException: Could not roll back Hibernate transaction; nested exception is org.hibernate.Tra
    nsactionException: Transaction not successfully started
            at org.springframework.orm.hibernate3.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:679)
            at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845)
            at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
            at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:412)
            at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:111)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
            at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
    Caused by: org.hibernate.TransactionException: Transaction not successfully started
            at org.hibernate.transaction.JDBCTransaction.rollback(JDBCTransaction.java:183)
            at org.springframework.orm.hibernate3.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:676)
            at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845)
            at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
            at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:412)
            at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:111)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
            at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
        ...
        ...
            at org.apache.catalina.valves.SSLValve.invoke(SSLValve.java:113)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
            at org.apache.coyote.http11.Http11NioProcessor.process(Http11NioProcessor.java:894)
            at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:719)
            at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:2101)
            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
            at java.lang.Thread.run(Thread.java:662)
    
  • PPP
    PPP over 12 years
    updated the question to make it more clear and with some exceptions I got with more debugging. I am no longer making any calls to rollback or commit since i am assuming that the @Transactional annotation already does that for me.
  • Ryan Stewart
    Ryan Stewart over 12 years
    Properly configured, @Transactional establishes declarative transaction boundaries where Spring will begin, commit, and roll back exceptions for you as appropriate. If you're doing anything like opening sessions or beginning, committing, or rolling back transactions yourself, that will interfere. The code you've posted has nothing apparently wrong, but it's only a tiny snippet and doesn't include any of your transaction configuration, either. The exception indicates something abnormal is happening because Spring will never try to commit/roll back a transaction that wasn't started.
  • PPP
    PPP over 12 years
    What transaction configuration do I need? spring is using the c3p0 connection pool in the backend for handling database connections. There is no statement that opens or starts any transaction or session on its own. there are only 2 statements in the function dealing with hibernate or session. I tried my own session and transaction stuff thinking that might be the problem but that didnt work either
  • PPP
    PPP over 12 years
    i already have something simliar in the config. <tx:annotation-driven transaction-manager="txManager" mode='proxy' proxy-target-class='true' /> and the bean config is the same except that the id='txManager'.
  • Ryan Stewart
    Ryan Stewart over 12 years
    Are you actually seeing partial commits/rollbacks, or are you just seeing things getting committed when an exception is thrown? Do you realize that checked exceptions don't trigger a rollback by default?
  • PPP
    PPP over 12 years
    I added a <tx:advice> section and added the attribute <tx:method name="*" rollback-for="Throwable" /> in it. What else do i need to do to ensure the transaction rollbacks?
  • PPP
    PPP over 12 years
    In my sql server logs, what i see is 'set autocommit=1' 'rollback' 'rollback' 'update table1 ...' 'insert into table2..' 'set autocommit=0' 'set autocommit=1' 'rollback' 'commit'
  • Ryan Stewart
    Ryan Stewart over 12 years
    That looks to me like autocommit is on. See #1 in my list. If autocommit is on, transactions are useless.
  • PPP
    PPP over 12 years
    how do I turn it off then? is it something I have to set in the mysql instance or somewhere in the spring config?
  • Ryan Stewart
    Ryan Stewart over 12 years
    It's been a long time since I used mysql. When I did, the default engine didn't support transactions at all, so you had to first be sure to use the InnoDB engine instead. Otherwise, you might find autocommit settings in your JDBC driver, your DataSource implementation, Hibernate, and/or possibly exposed through Spring somewhere. You'd just have to look around. In general, autocommit should already be off, so there's probably something fishy somewhere. I'd check the database engine first.