spring事务里面开启线程插入报错了会回滚吗

其他教程   发布日期:2025年03月10日   浏览次数:134

这篇文章主要讲解了“spring事务里面开启线程插入报错了会回滚吗”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“spring事务里面开启线程插入报错了会回滚吗”吧!

1.前言

一道非常有意思的面试题目。大概是这样子的,如果在一个事务中,开启线程进行插入更新等操作,如果报错了,事务是否会进行回滚。

2.代码

示例1

  1. @RequestMapping("/test/publish/submit")
  2. public String testPublish2() {
  3. log.info("start...");
  4. transactionTemplate.execute(new TransactionCallback<String>() {
  5. @Override
  6. public String doInTransaction(TransactionStatus status) {
  7. TElement element = new TElement();
  8. element.setfElementId(10L);
  9. element.setfElementName("111");
  10. mapper.insertSelective(element);
  11. element = new TElement();
  12. element.setfElementId(10L);
  13. element.setfElementName("222");
  14. mapper.insertSelective(element);
  15. return "OK";
  16. }
  17. });
  18. log.info("end...");
  19. return "ok";
  20. }

示例2

  1. @RequestMapping("/test/publish/submit2")
  2. public String testPublish3() {
  3. log.info("start...");
  4. transactionTemplate.execute(new TransactionCallback<String>() {
  5. @Override
  6. public String doInTransaction(TransactionStatus status) {
  7. es.submit(() -> {
  8. TElement element = new TElement();
  9. element.setfElementId(10L);
  10. element.setfElementName("111");
  11. mapper.insertSelective(element);
  12. });
  13. es.submit(() -> {
  14. TElement element = new TElement();
  15. element.setfElementId(10L);
  16. element.setfElementName("222");
  17. mapper.insertSelective(element);
  18. });
  19. return "OK";
  20. }
  21. });
  22. log.info("end...");
  23. return "ok";
  24. }

3.结论

示例1

element.setfElementId(10L); 为主键。SQL在第一次插入id=10的时候是没有问题的,在第二次插入id=10的时候,由于主键冲突了,导致报错,然后整个事务都会进行回滚,这是没有问题的。是spring的事务帮助我们来进行回滚等操作的。我们可以看到如下代码,他是对整个result = action.doInTransaction(status);进行了try catch。如果抛异常,就会回滚

  1. @Override
  2. @Nullable
  3. public <T> T execute(TransactionCallback<T> action) throws TransactionException {
  4. Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
  5. if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
  6. return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
  7. }
  8. else {
  9. TransactionStatus status = this.transactionManager.getTransaction(this);
  10. T result;
  11. try {
  12. result = action.doInTransaction(status);
  13. }
  14. catch (RuntimeException | Error ex) {
  15. // Transactional code threw application exception -> rollback
  16. rollbackOnException(status, ex);
  17. throw ex;
  18. }
  19. catch (Throwable ex) {
  20. // Transactional code threw unexpected exception -> rollback
  21. rollbackOnException(status, ex);
  22. throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
  23. }
  24. this.transactionManager.commit(status);
  25. return result;
  26. }
  27. }

示例2

示例2首先是transactionTemplate.execute是一个主main线程。然后在第一个子线程插入了一个数据,第二个子线程也插入了一个数据。那么现在就是有三个线程,一个是main线程,一个是A线程,一个是B线程。
main线程正常执行不报错,A线程正常插入不报错,B线程由于主键冲突报错。
我们可以通过上面action.doInTransaction(status);看出来,他对这块代码进行了try catch。也就是主线程进行了try catch。那么也就是只要主线程没有报错,这个事务就不会被捕获,也就不会回滚了。无论你A,B还是CDEFG子线程出问题了,只要不影响main线程,那事务就不会回滚呢?
因此我们可以得出一个结论,在示例2中,A线程会插入成功,B线程插入失败,事务不会回滚,最终插入成功。这个其实与我们平常的想法所违背了。
因此如果想要主线程抛出异常,得让主线程感知到子线程异常了,主动地去throw异常。比如我们可以设置一个flag,子线程报错了 flag=true。主线程检测到flag为true,就主动抛出一个exception

以上就是spring事务里面开启线程插入报错了会回滚吗的详细内容,更多关于spring事务里面开启线程插入报错了会回滚吗的资料请关注九品源码其它相关文章!