Spring事务


什么是事务?

我们在开发企业应用时,对于业务人员的一个操作实际是对数据读写的多步操作的结合。由于数据操作在顺序执行的过程中,任何一步操作都有可能发生异常,异常会导致后续操作无法完成,此时由于业务逻辑并未正确的完成,之前成功操作数据的并不可靠,需要在这种情况下进行回退。

事务的作用就是为了保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,只要有发生异常就回退到事务开始未进行操作的状态。

Spring Boot事务配置

1、在启动主类添加注解:@EnableTransactionManagement 来启用注解式事务管理,相当于之前在xml中配置的<tx:annotation-driven />注解驱动(可加可不加,@SpringBootApplication里的@EnableAutoConfiguration已经提供相同功能)。

2、在需要事务的类或者方法上面添加@Transactional() 注解,里面可以配置需要的粒度:

属性类型描述
valueString可选的限定描述符,指定使用的事务管理器
porpagationenum: Propagation可选的事务传播行为设置
isolationenum: Isolation可选的事务隔离级别设置
readOnlyboolean读写或只读事务,默认读写
timeoutint (in seconds granularity)事务超时时间设置
rollbackForClass对象数组,必须继承自Throwable导致事务回滚的异常类数组
rollbackForClassName类名数组,必须继承自Throwable导致事务回滚的异常类名字数组
noRollbackForClass对象数组,必须继承自Throwable不会导致事务回滚的异常类数组
noRollbackForClassName类名数组,必须继承自Throwable不会导致事务回滚的异常类名字数组

常见坑点1:

例如下面这段代码,账户余额依旧增加成功,并没有因为后面遇到SQLException(检测异常)而进行事务回滚!!

@Transactional 
public void addMoney() throws Exception { 
    //先增加余额 
    accountMapper.addMoney();
    //然后遇到故障 
    throw new SQLException("发生异常了.."); 
 }

原因分析:因为Spring的默认的事务规则是遇到运行异常(RuntimeException及其子类)和程序错误(Error)才会进行事务回滚,显然SQLException并不属于这个范围。如果想针对检测异常进行事务回滚,可以在@Transactional 注解里使用rollbackFor 属性明确指定异常。例如下面这样,就可以正常回滚:

 @Transactional(rollbackFor = Exception.class) 
 public void addMoney() throws Exception { 
     //先增加余额 
     accountMapper.addMoney(); 
     //然后遇到故障 
     throw new SQLException("发生异常了.."); 
 }

常见坑点2: 在业务层捕捉异常后,发现事务不生效。

在业务层手工捕捉并处理了异常,你都把异常“吃”掉了,Spring自然不知道这里有错,更不会主动去回滚数据。例如:下面这段代码直接导致增加余额的事务回滚没有生效。

@Transactional 
public void addMoney() throws Exception { 
    //先增加余额 
    accountMapper.addMoney(); 
    //谨慎:尽量不要在业务层捕捉异常并处理 
    try { 
        throw new SQLException("发生异常了.."); 
    } catch (Exception e) { 
        e.printStackTrace(); 
    } 
}

推荐做法:若非实际业务要求,则在业务层统一抛出异常,然后在控制层统一处理。

@Transactional 
public void addMoney() throws Exception { 
    //先增加余额 
    accountMapper.addMoney(); 
    //推荐:在业务层将异常抛出 
    throw new RuntimeException("发生异常了.."); 
}

事务的传播属性

REQUIRES_NEW:

启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。他是其一个单独的事务,自我完全隔离。

REQUIRED:

如果当前存在一个事务,则加入当前事务。如果不存在任何事务,则创建一个新的事务。他可能会两个事务合并成一个,或外部没有事务时自己创建一个事务。一般作为事务默认的传播行为。

声明:佐手丶|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - Spring事务


Carpe Diem and Do what I like