广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Spring事务管理中的异常回滚是什么
  • 164
分享到

Spring事务管理中的异常回滚是什么

Python 官方文档:入门教程 => 点击学习

摘要

目录前言问题场景spring 管理事务的原理Mysql中的事务管理JDBC中的事务管理Spring中的事务管理Spring中的事务接口到底回滚还是不回滚简明答案什么是执行事务的方法什

记录总结Spring核心知识点:事务使用与它的传播机制

前言

这里不打算讨论Spring底层源码,只讨论测试场景和总结. 不断整理让大脑中的知识体系沉淀。

问题场景

项目系统中,serviceA 中调用的 serviceB ,并且对 serviceB 进行 tryCache

@Service("testAService")
public class TestAServiceImpl implements TestAService {
    @Resource
    private TestAMapper testAMapper;
    @Resource
    private TestBService testBService;
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void saveTestA(TestA entity) {
        testAMapper.insertSelective(entity);
        try {
            testBService.saveTestB(new TestB());
        } catch (Exception e) {
            logger.error("调用B失败", e);
        }
        // 模拟做其他的数据库操作事情
        testAMapper.updateSelective(entity);
    }
}

testBService 中模拟抛出异常:

@Service("testBService")
public class TestBServiceImpl mplements TestBService {
    @Resource
    private TestBMapper testBMapper;
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public void saveTestB(TestB entity) {
        testBMapper.insertSelective(entity);
        throw new RuntimeException("自定义异常");
    }
}

问 在Controller层中调用 TestAService.saveTestA() 会怎么样?

    @Resource
    private TestAService testAService;
    @apiOperation(value = "Spring事务嵌套测试")
    @GetMapping("springTransactionTest")
    public ResponseVO<NoBody> springTransactionTest() {
        testAService.saveTestA(new TestA());
        return ResponseVO.success();
    }

答案是:

testAService testBService 中的数据库操作 全部回滚,并且抛出的错误异常:

Transaction rolled back because it has been marked as rollback-only

原因是:

testBService.saveTestB 也增加了同样的事务注解 @Transactional

且事务隔离机制为 “REQUIRED” ,因此 两方法执行期间为同一个数据库事务,被同一个Spring事务管理器所管理着。

由于最开始开启事务者为 testAService.saveTestA,则真正执行回滚操作在 saveTestA 方法中 (Spring 规定了只有新创建的事务才会真正进行提交或回滚),

因此 saveTestB 方法中异常时只设置了当前事务状态为 RollbackOnly

org.springframework.jdbc.datasource.DataSourceTransactionManager#doSetRollbackOnly

虽然 saveTestA 中 tryCache 了 saveTestB 中的异常,企图吃掉异常信息让 saveTestA 中的事务正常提交,但是 saveTestB 里面已经设置了 当前事务状态为 RollbackOnly, 出现了冲突矛盾!

因此事务全部回滚,并且抛出异常信息:

 Transaction rolled back because it has been marked as rollback-only

Spring 管理事务的原理

首先,事务一般是关系型数据库中的概念,主要目的就是 保证一系列的增删改 sql操作 要么全部成功,要么全部回滚。

mysql中的事务管理

在MySQL中采用SQL命令进行事务管理:

  • START TRANSACTION 或 BEGIN 或 SET autocommit = 0 开启事务
  • 执行 CRUD
  • COMMIT 提交事务
  • ROLLBACK 回滚事务

这里重点说下 多条SQL在一个事务中,其中有部分SQL执行失败情况下,最终执行结果是什么

> begin;
> insert_sql1 (insert into test1(id,name)value(1,'aaa')) ;
> insert_sql2 (insert into test2(id,name)value(1,'bbb')) ;
> commit/ rollback;

上面示意代码,如果 insert_sql1 成功, insert_sql2 失败时,请问 insert_sql1 最终是否插入成功?

答案是:

首先事务不会马上回滚, 其次如果 此时执行commit则 insert_sql1 会插入成功 ,如果执行rollback则insert_sql1 会回滚。

那一般事务什么时候自动回滚或者自动提交?这里记录一下常见场景:

  • 如果事务执行中出现 DDL语句( alert create drop truncate等 ) 事务自动 commit;
  • 如果事务执行中又开启了一个事务(又出现 begin; sql命令)事务自动 commit;
  • 如果执行SQL的session 中途被关闭(SQL窗口关闭,服务器断电等) 事务自动 rollback;

JDBC中的事务管理

JDBC中连接数据库进行事务管理:

  • 获取连接 Connection con = DriverManager.getConnection()
  • con.setAutoCommit(true/false); 开启事务
  • 执行CRUD
  • con.commit() ; 提交事务
  • con.rollback(); 回滚事务
  • 关闭连接 conn.close();

JDBC 事务管理的本质还是连接了数据库执行各类数据库中开启关闭事务的SQL命令

Spring中的事务管理

Spring通过自身aop切面功能,代理各个业务方法调用 JDBC中的方法进行开启、关闭、提交、回滚事务等操作。

至于嵌套事务、各类传播机制是如何实现, 这里简单总结,虽然不能体现Spring 事务操作方面的强大,但可以很快有个大致理解。

Spring 通过 一个Map 存放了当前数据库连接对象,这是为了解决根据设定的传播机制 ( propagation ) 决定是否要新开一个事务,新开另外一个事务需要重新申请一个数据库连接。

Spring 通过 数据库事务中的 SAVEPOINT 保留点功能实现 嵌套事务的传播机制。

这里记录一下一个Http请求 从Controller层发起数据库操作请求到回滚的log日志,用于加强理解:

    @ApiOperation(value = "事务回滚测试")
    @PostMapping("rollbackTest")
    public ResponseVO<NoBody> rollbackTest() {
        // 简单模拟插入一条记录
        testAService.saveTestA(new TestA());
        return ResponseVO.success();
    }

[http-NIO-9902-exec-5] o.s.WEB.servlet.DispatcherServlet        : POST "/api/rollbackTest", parameters={}
[http-nio-9902-exec-5] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.guzt.main.model.test.web.DbTestController#rollbackTest()
[http-nio-9902-exec-5] o.s.j.d.DataSourceTransactionManager     : Creating new transaction with name [com.sdjictec.wms.main.model.test.service.impl.TestAServiceImpl.saveTestA]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Exception
[http-nio-9902-exec-5] o.s.j.d.DataSourceTransactionManager     : Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@7fec11ca] for JDBC transaction
[http-nio-9902-exec-5] o.s.j.d.DataSourceTransactionManager     : Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@7fec11ca] to manual commit
[http-nio-9902-exec-5] c.s.w.m.m.t.d.T.insertSelective          : ==>  Preparing: INSERT INTO t_test_a ( ID,NAME ) VALUES(?,? )
[http-nio-9902-exec-5] c.s.w.m.m.t.d.T.insertSelective          : ==> Parameters: 1655001437939(String), p4xfy8(String)
[http-nio-9902-exec-5] c.s.w.m.m.t.d.T.insertSelective          : <==    Updates: 1
[http-nio-9902-exec-5] o.s.j.d.DataSourceTransactionManager     : Initiating transaction rollback
[http-nio-9902-exec-5] o.s.j.d.DataSourceTransactionManager     : Rolling back JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@7fec11ca]
[http-nio-9902-exec-5] o.s.j.d.DataSourceTransactionManager     : Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@7fec11ca] after transaction
[http-nio-9902-exec-5] c.s.w.m.c.p.context.CurrentUserContext   : CurrentUserContext remove CurrentUserVO...
[http-nio-9902-exec-5] c.s.w.m.f.a.CurrentUserContextAspect     : CurrentUserContextAspect doAfterThrowing  CurrentUserContext.remove()...
[http-nio-9902-exec-5] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler com.guzt.main.framework.exception.GlobalExceptionHandler#handleBusinessException(BusinessException)
[http-nio-9902-exec-5] c.s.w.m.f.e.GlobalExceptionHandler       : BusinessException -- errorCode:E5111 errORMsg:模拟数据库操作异常,主键重复
[http-nio-9902-exec-5] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/JSON', given [*/*] and supported [application/json, application/json, application/*+json, application/json, application/*+json, application/cbor]
[http-nio-9902-exec-5] m.m.a.RequestResponseBodyMethodProcessor : Writing [ResponseVO(code=-1, message=模拟数据库操作异常,主键重复, data={"errorBody":"","bussinessCode":"E5111","extraMsg":""})]
[http-nio-9902-exec-5] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [com.guzt.starter.common.exception.BusinessException: errorCode=E5111, errorMsg=FAIL]
[http-nio-9902-exec-5] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

主要的步骤:

Creating new transaction

DataSourceTransactionManager 根据 TransactionDefinition 创建 TransactionStatus 对象,准备开启事务Acquired Connection for JDBC transaction

通过数据库连接池 申领一个数据库连接Switching JDBC Connection to manual commit

开启事务,底层是通过JDBC执行 SET autocommit = 0; Initiating transaction rollback

准备回滚事务,修改 TransactionStatus 状态为回滚Rolling back JDBC transaction

回滚事务 ,底层是通过JDBC执行 rollback; SET autocommit = 1;Releasing JDBC Connection

释放数据库连接,最后是关闭了数据库连接,底层调用了 JDBC Connection.close()

Spring中的事务接口

上面日志中提到了 TransactionDefinition TransactionStatus 等接口,这里也顺便总结一下Spring事务中重要的几个接口。

接口含义说明
PlatformTransactionManager事务管理器各类数据库操作框架自行实现该接口,例如 DataSourceTransactionManager(JDBC), JtaTransactionManager, HibernateTransactionManager
TransactionDefinition事务定义信息(隔离级别、传播行为、超时、只读、回滚规则) ,
一般在@Transactional 中指定这些属性
如果是注解方式的事务,Spring 通过 AnnotationTransactionAttributeSource.getTransactionAttribute(Method method, Class<?> targetClass) 创建,参数中的method就是开启事务的业务方法
TransactionStatus事务运行状态,包含是否已完成,是否只读,是否有恢复点,是否只回滚等事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务

至于具体功能流程,这里不讨论,自行看源码,多debug即可明白。

到底回滚还是不回滚

本次讨论重点就是 Spring的事务管理中,遇到了程序异常到底会不会回滚?

简明答案

执行事务的方法如果感知到了异常则将回滚事务

什么是执行事务的方法

一般方法上增加了 @Transactional 注解或 其他Spring事务支持的方式AOP代理了的方法

  @Transactional
   public void saveTestA(TestA entity) {
        业务代码
   }

什么情况下异常被感知

被Spring事务AOP所代理的业务方法执行时出现异常,且异常类在Spring事务回滚范围内的将被调用方法所感知。

默认Spring只对 unchecked Exception 进行回滚,一般手动设定全部异常(rollbackFor = Exception.class)

什么情况下异常不被感知

一般这是讨论事务不生效的场景。

  • 方法访问修饰符非public
  • 法抛出的异常不是spring的事务支持的异常
  • 被 Try-Cache 捕获且不再向外抛出例如下面的场景代码:
   @Transactional
   public void saveTestA(TestA entity) {
     try{
        业务代码
     } catch (Exception e) {
         logger.error("内部消化异常,不往外抛", e);
     }
   }

注解所在的类没有被Spring 事务AOP代理

这种场景问题最隐蔽,一般需要有经验或者多次debug才能发现

同一个类里面方法互相调用,一般建议采用 SpringUtil.getBean(this.getClass()).xxxx事务方法()

某些策略模式场景,需要将service对象放到一个 Map<String, Service>中 ,如果是自行放置,则对象必须是 代理对象而非 this对象,建议采用 SpringUtil.getBean(this.getClass()) 对象。

参考代码:

public class WxinOrderTypeServiceImpl implements OrderTypeService {
  @PostConstruct
  public void init() {
      ORDER_TYPE_SERVICE.put("orderTypeKey", SpringUtil.getBean(this.getClass());
  }
  @Transactional(rollbackFor = Exception.class)
  @Override
  public void saveOrder(Order order)
    logger.info("微信订单");
  }
}

上面代码意思是,将Spring代理的对象 WxinOrderTypeServiceImpl$Cjlibxxxx 放置到策略map ORDER_TYPE_SERVICE中去,如果用 this ( ORDER_TYPE_SERVICE.put("orderTypeKey",this)) 则事务不生效,因为this虽然也在Spring beanFactory中但没有被事务AOP所代理,因此用this 会不生效。

备注: SpringUtil 其实就是实现了接口 ApplicationContextAware 获得ApplicationContext,ApplicationContext 中有 getBean方法,当然SpringBoot 可以在业务类里面直接注入 ApplicationContext

@Autowired
ApplicationContext applicationContext;

数据库本身不支持事务

如果使用MySQL且存储引擎是MyISAM,则事务是不起作用的

异常被感知后Spring做些什么

异常被感知后,Spring将会做回滚或更新TransactionStatus的状态(doSetRollbackOnly).

一旦TransactionStatus 被打上了 RollbackOnly标志后,那么不管中间的业务代码是什么 都会抛出异常进行全部事务回滚。

那么什么时候 不做回滚只更新 TransactionStatus 为 RollbackOnly?

参见文章一开始的业务代码,同属于一个事务中(Propagation.REQUIRED)的多个执行事务方法(业务代码中嵌套调用其他service方法),如果不是首次开启事务的那个方法则都只会更新 TransactionStatus 为 RollbackOnly,事务的提交回滚由首次事务开启的那个方法执行

参见源码 org.springframework.transaction.support.AbstractPlatformTransactionManager# processRollback

回滚程度是多少

事务回滚到哪一个程度,是全部嵌套调用的方法都回滚还是部分方法回滚,这里主要是由Spring的事务传播机制功能控制。

分类行为说明回滚程度
加入当前事务PROPAGATION_REQUIRED默认方式,如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务全部回滚
加入当前事务PROPAGATION_SUPPORTS如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行全部回滚
加入当前事务PROPAGATION_MANDATORY如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常全部回滚
不加入当前事务PROPAGATION_REQUIRES_NEW创建一个新的事务,则把当前事务挂起Java里面还是同一个线程,只新创建了另外一个数据库连接开启事务,如果新事务回滚且程序异常被当前事务方法感知,则当前事务方法也同样回滚
不加入当前事务PROPAGATION_NOT_SUPPORTED以非事务方式运行,如果当前存在事务,则把当前事务挂起Java里面还是同一个线程 如果程序异常被当前事务方法感知,则当前事务方法也同样回滚
不加入当前事务PROPAGATION_NEVER以非事务方式运行,如果当前存在事务,则抛出异常抛出异常,全部回滚
嵌套当前事务PROPAGATION_NESTED如果当前存在事务,则创建一个事务嵌套在当前事务中运行;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED只回滚自己  底层采用数据库SavePoint功能

到此这篇关于Spring事务管理中的异常回滚是什么的文章就介绍到这了,更多相关Spring异常回滚内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Spring事务管理中的异常回滚是什么

本文链接: https://www.lsjlt.com/news/195415.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring事务管理中的异常回滚是什么
    目录前言问题场景Spring 管理事务的原理MySQL中的事务管理JDBC中的事务管理Spring中的事务管理Spring中的事务接口到底回滚还是不回滚简明答案什么是执行事务的方法什...
    99+
    2023-02-09
    Spring事务管理异常回滚 Spring异常回滚 Spring事务管理中的异常回滚
  • Spring事务管理中的异常回滚案例分析
    这篇文章主要介绍了Spring事务管理中的异常回滚案例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Spring事务管理中的异常回滚案例分析文章都会有所收获,下面我们一起来看看吧。问题场景某项目系统中,se...
    99+
    2023-07-05
  • Spring事务捕获异常后依旧回滚的解决
    目录前沿问题阐述知识点前置条件问题追踪总结前沿 一段生产事故发人深省,在Spring的声明式事务中手动捕获异常,居然判定回滚了,这是什么操作?话不多说直接上代码 @Service p...
    99+
    2022-11-12
  • mysql事务回滚的原理是什么
    MySQL中的事务回滚是通过将数据库恢复到事务开始之前的状态来实现的。事务回滚的原理如下:1. MySQL使用日志来记录所有对数据库...
    99+
    2023-10-09
    mysql
  • mongodb回滚事务的原理是什么
    MongoDB回滚事务的原理是基于写操作的日志记录和持久化。当执行一个事务时,MongoDB会将所有的写操作记录到一个称为oplog...
    99+
    2023-10-26
    mongodb
  • 浅谈Spring嵌套事务是怎么回滚的
    目录源码解析TransactionAspectSupport.invokeWithinTransaction()内层事务TransactionAspectSupport.comple...
    99+
    2022-11-12
  • Spring中什么是统一异常处理
    这篇文章主要介绍“Spring中什么是统一异常处理”,在日常操作中,相信很多人在Spring中什么是统一异常处理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Spring中什...
    99+
    2022-10-19
  • spring全局异常处理的原理是什么
    Spring全局异常处理的原理是通过定义一个统一的异常处理器来捕获和处理应用程序中的任何异常。当应用程序发生异常时,Spring会将...
    99+
    2023-10-20
    spring
  • Spring MVC异常解析器的原理是什么
    本篇内容主要讲解“Spring MVC异常解析器的原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring MVC异常解析器的原理是什么”吧!使用介...
    99+
    2022-10-19
  • Spring Cloud中Hystrix服务降级与异常处理的方法是什么
    本篇内容主要讲解“Spring Cloud中Hystrix服务降级与异常处理的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring Cloud中Hystrix服务降级与异常处理的...
    99+
    2023-06-19
  • Spring MVC的拦截器与异常处理机制是什么
    这篇文章主要介绍了Spring MVC的拦截器与异常处理机制是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Spring MVC的拦截器与异常处理机制是什么文章都会有所收获,下面我们一起...
    99+
    2023-06-29
  • Spring访问数据库异常的处理方法是什么
    Spring访问数据库异常的处理方法是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。使用JDBC API时,很多操作都要声明抛出java.sql.SQLExceptio...
    99+
    2023-06-17
  • Spring框架JdbcTemplate数据库事务管理完全注解方式是什么
    这篇“Spring框架JdbcTemplate数据库事务管理完全注解方式是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“...
    99+
    2023-06-30
  • PHP中的异常处理机制是什么?
    PHP是一种开源脚本语言,广泛应用于Web开发中。它有一个强大的异常处理机制,有助于开发人员更好地捕获并处理程序中的错误和异常。一、什么是异常?在编写程序时,会发生各种错误,比如无法找到文件、变量类型不匹配、数组越界等等。这些错误也称为异常...
    99+
    2023-05-14
    机制 PHP 异常处理
  • Struts2中的异常处理机制是什么
    这期内容当中小编将会给大家带来有关Struts2中的异常处理机制是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。声明式异常捕捉Struts2的异常处理机制是通过在struts.xml文件中配置<...
    99+
    2023-05-31
    struts2 st 异常处
  • Python中的异常处理方法是什么
    这篇文章主要介绍“Python中的异常处理方法是什么”,在日常操作中,相信很多人在Python中的异常处理方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python中的异常处理方法是什么”的疑惑有所...
    99+
    2023-07-06
  • python中异常处理的方法是什么
    Python中的异常处理方法是使用`try-except`语句块来捕获和处理异常。以下是一些常见的异常处理方法:1. 使用`try-...
    99+
    2023-08-08
    python
  • Java Spring AOP源码解析中的事务实现原理是什么
    这篇文章将为大家详细讲解有关Java Spring AOP源码解析中的事务实现原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。不用Spring管理事务?让我们先来...
    99+
    2023-06-22
  • Spring中编程式事务与声明式事务的区别是什么
    本篇文章为大家展示了Spring中编程式事务与声明式事务的区别是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Spring事务属性我们都知道事务有开始,保存点,提交,回滚,隔离级别等属性。那么S...
    99+
    2023-05-31
    spring 别是
  • java中异常处理机制的原理是什么
    Java中的异常处理机制是基于异常类的继承关系和异常处理代码块的机制。当程序发生异常时,会抛出一个异常对象,该异常对象会沿着调用链向...
    99+
    2023-08-31
    java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作