Spring声明式事务不回滚

发布于 2024-12-23 14:31:58 字数 1977 浏览 1 评论 0原文

我创建了一个简单的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月牙弯弯 2024-12-30 14:31:58

使用 @TransactionConfiguration("名称",ROLLBACK); //声明TrxHandleAnnotated时在@Transactional之后检查语法。有关 @Transcational 及其的更多信息,请参阅此链接用法。

use @TransactionConfiguration("name",ROLLBACK); //check syntax after @Transactional while declaring TrxHandleAnnotated. see this link for more information about @Transcational and its usage.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文