Spring声明式事务不回滚
我创建了一个简单的 Spring 应用程序来测试 Spring 声明式事务的基础知识。 根据规则,声明式事务应该在发生 RuntimeException 时回滚。 但就我而言,它并没有回滚。
主测试类有代码
public class SpringOraTest {
public static void main(String[] args) {
ApplicationContext aplctx= new
FileSystemXmlApplicationContext("src\\config\\SpringConfigForOra.xml");
//Call to test Declarative Transaction with Annotation
TrxHandleAnnotated prxyobj=((TrxHandleAnnotated)aplctx.getBean("dbCommandAnnotated"));
prxyobj.doTask();
}
}
TrxHandleAnnotated 类有代码:-
@Transactional
public class TrxHandleAnnotated
public void doTask(){
ApplicationContext aplctx= new
FileSystemXmlApplicationContext("src\\config\\SpringConfigForOra.xml");
JdbcTemplate jdbcTemplate= (JdbcTemplate)aplctx.getBean("jdbcTemplate");
jdbcTemplate.update("insert into kau_emp values(4,'forthmulga' )");
throw new RuntimeException();
}
并且配置 XML 中有必需的配置。
我期望在抛出异常时回滚事务。但它并没有被回滚,并且记录被提交给数据库。
即使在互联网上进行了长时间的搜索后,我也不明白为什么它没有被回滚。
后来我意识到,在 doTask() 代码中,我再次创建上下文,并将 JdbcTemplate 实例从新上下文中取出。这是问题的根本原因。
我更改了代码,使两个类都将使用一些上下文。它起作用了!
public class SpringOraTest {
public static ApplicationContext aplctx;
public static void main(String[] args) {
aplctx= new FileSystemXmlApplicationContext("src\\config\\SpringConfigForOra.xml");
//Call to test Declarative Transaction with Annotation
TrxHandleAnnotated prxyobj=
((TrxHandleAnnotated)aplctx.getBean("dbCommandAnnotated"));
prxyobj.doTask();
}
@Transactional
public class TrxHandleAnnotated
public void doTask(){
JdbcTemplate jdbcTemplate=(JdbcTemplate)SpringOraTest.aplctx.getBean("jdbcTemplate");
jdbcTemplate.update("insert into kau_emp values(4,'forthmulga' )");
throw new RuntimeException();
}
这对我来说是一个教训,除非另有要求,否则整个应用程序应该仅使用一个上下文对象。
对于 Spring 从业者来说,这听起来太明显了,但像我这样的 Spring 新手可能会犯这样愚蠢的错误。于是想到分享一下。
在这种特殊情况下,最好将其声明为成员变量并使用 setter 注入,而不是手动创建 JdbcTemplate。
I created a simple spring application to test the basics of Spring declarative transaction.
As per rules declarative transaction should rollback in case of RuntimeException.
But it was not rolling back in my case.
Main test class has code
public class SpringOraTest {
public static void main(String[] args) {
ApplicationContext aplctx= new
FileSystemXmlApplicationContext("src\\config\\SpringConfigForOra.xml");
//Call to test Declarative Transaction with Annotation
TrxHandleAnnotated prxyobj=((TrxHandleAnnotated)aplctx.getBean("dbCommandAnnotated"));
prxyobj.doTask();
}
}
The class TrxHandleAnnotated had code :-
@Transactional
public class TrxHandleAnnotated
public void doTask(){
ApplicationContext aplctx= new
FileSystemXmlApplicationContext("src\\config\\SpringConfigForOra.xml");
JdbcTemplate jdbcTemplate= (JdbcTemplate)aplctx.getBean("jdbcTemplate");
jdbcTemplate.update("insert into kau_emp values(4,'forthmulga' )");
throw new RuntimeException();
}
And there was required configuration in config XML.
I was expecting that transaction be rolled back when exception is thrown. But it was not rolled back and record was getting commited to DB.
Even after long search on internet I could not understand why it was not getting rolled back.
Later I realised that, in doTask() code I am creating context once again and taking our JdbcTemplate instance out of new context it. This was the root cause of the issue.
I changed the code such a way that both classes will use some context. And it worked !!!
public class SpringOraTest {
public static ApplicationContext aplctx;
public static void main(String[] args) {
aplctx= new FileSystemXmlApplicationContext("src\\config\\SpringConfigForOra.xml");
//Call to test Declarative Transaction with Annotation
TrxHandleAnnotated prxyobj=
((TrxHandleAnnotated)aplctx.getBean("dbCommandAnnotated"));
prxyobj.doTask();
}
@Transactional
public class TrxHandleAnnotated
public void doTask(){
JdbcTemplate jdbcTemplate=(JdbcTemplate)SpringOraTest.aplctx.getBean("jdbcTemplate");
jdbcTemplate.update("insert into kau_emp values(4,'forthmulga' )");
throw new RuntimeException();
}
This is a lesson-learnt for me that, unless otherwise required, whole application should use only one context object.
This will sound too obvious Spring practitioners but spring novice like me can do such silly mistakes. So thought of sharing it.
In this particular case instead of manually creating JdbcTemplate is better to declare it as member variable and use setter injection.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
使用 @TransactionConfiguration("名称",ROLLBACK); //声明
TrxHandleAnnotated
时在@Transactional之后检查语法。有关 @Transcational 及其的更多信息,请参阅此链接用法。use
@TransactionConfiguration("name",ROLLBACK); //check syntax
after @Transactional while declaringTrxHandleAnnotated
. see this link for more information about @Transcational and its usage.