Mateus Arruda
Mateus Arruda

Reputation: 305

How to rollback a transactional database operation and save the error message into another table?

I'm using Spring and Hibernate trying to update a value of the database. It is needed that, in case of exceptions, save the error message into a table. I'm facing some errors because when I'm able to save the message into the database, the transaction doesn't rollback. Here is the pseudo-code

@Transactional
public class ObjectTable(){
    //instanciate other objects
    RelatedObject relatedObject = relatedObjectController.getObjectById(primaryKey)
    Object object =  objectController.getObjectByRelatedObject(relatedObject.getPrimaryKey())



    @Transactional(rollbackFor = Exception.class)
    public updateObject(Object object) throws MyCustomException{
         try{
             getHibernateTemplate().getSessionFactory.getCurrentSession().evict(object);
             getHibernateTemplate().getSessionFactory.getCurrentSession().saveOrUpdate(object);
             getSession.flush();
         }catch(Exception ex){
              saveErrorMessageIntoDatabase(ex.getMessage, this.relatedObject);
              throw new MyCustomException(ex.getMessage)
         }
    }

    public saveErrorMessageIntoDatabase(String message, RelatedObject relatedObject){
         relatedObject.setErrorMessage(message);
         getHibernateTemplate().getSessionFactory.getCurrentSession().evict(relatedObject);
         getHibernateTemplate().getSessionFactory.getCurrentSession().saveOrUpdate(relatedObject);
         getSession.flush();
    }

}

With this kind of tought, I'm not being able to save the message in relatedObject and rollback the changes in object. Making a few variations, such as putting a propagation = Propagation.REQUIRES_NEW or propagation = Propagation.REQUIRED or removing the Excpection.class for rollback, I get some other behaviours, like save the error message but also writes the changes of object when there is an exception, or rollin back the changes but also not writing the error message into relatedObject.

I also tried with merge instead of saveOrUpdate, but with no success.

Could someone help me write a way to rollback changes in case of error but also save the error message into the database?

Thank you.

*I don't post the actual code because this is not a personal project.

EDIT: My transactionManager is configured as a XML bean where first I create the objectTableTarget setting the sessionFactory property and bellow that I set another bean objectTable refering to the methods I want to set as transactional.

<bean id="objectTableTarget" class="br.com.classes.ObjectTable" singleton="true">
        <property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="objectTable" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="transactionManager" />
    <property name="target" ref="objectTableTarget" />

    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
            <prop key="updateObject*">PROPAGATION_REQUIRED,-br.com.package.exception.MyCustomException</prop>
        </props>
    </property>
</bean>

Upvotes: 1

Views: 835

Answers (1)

Yevhen Surovskyi
Yevhen Surovskyi

Reputation: 961

move your log method into separate service and annotate it with @Transactional(propagation = Propagation.REQUIRES_NEW)

    @Service
    public class ErrorLoggerService(){
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public saveErrorMessageIntoDatabase(String message, RelatedObject relatedObject){
             relatedObject.setErrorMessage(message);
             getHibernateTemplate().getSessionFactory.getCurrentSession().evict(relatedObject);
             getHibernateTemplate().getSessionFactory.getCurrentSession().saveOrUpdate(relatedObject);
             getSession.flush();
        }
}

Then spring can create proxy on your method and error should be write in new transaction

Upvotes: 1

Related Questions