英文:
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(){
// instantiate 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 thought, I'm not being able to save the message in relatedObject
and rollback the changes in object
. Making a few variations, such as putting propagation = Propagation.REQUIRES_NEW
or propagation = Propagation.REQUIRED
or removing the Exception.class
for rollback, I get some other behaviors, like saving the error message but also writing the changes of object
when there is an exception, or rolling 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 an 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 an XML bean where first I create the objectTableTarget
setting the sessionFactory
property and below that I set another bean objectTable
referring 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>
Note: I've made some corrections to your code, including fixing method calls and adding missing parentheses.
英文:
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>
答案1
得分: 1
将您的日志方法移到一个独立的服务中,并使用以下方式进行注解:
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Service
public class ErrorLoggerService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveErrorMessageIntoDatabase(String message, RelatedObject relatedObject) {
relatedObject.setErrorMessage(message);
getHibernateTemplate().getSessionFactory().getCurrentSession().evict(relatedObject);
getHibernateTemplate().getSessionFactory().getCurrentSession().saveOrUpdate(relatedObject);
getSession().flush();
}
}
然后,Spring 将为您的方法创建代理,并在新的事务中记录错误。
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论