什么是事务?
我们在开发企业应用时,对于业务人员的一个操作实际是对数据读写的多步操作的结合。由于数据操作在顺序执行的过程中,任何一步操作都有可能发生异常,异常会导致后续操作无法完成,此时由于业务逻辑并未正确的完成,之前成功操作数据的并不可靠,需要在这种情况下进行回退。
事务的作用就是为了保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,只要有发生异常就回退到事务开始未进行操作的状态。
Spring Boot事务配置
1、在启动主类添加注解:@EnableTransactionManagement
来启用注解式事务管理,相当于之前在xml中配置的<tx:annotation-driven />
注解驱动(可加可不加,@SpringBootApplication里的@EnableAutoConfiguration已经提供相同功能)。
2、在需要事务的类或者方法上面添加@Transactional()
注解,里面可以配置需要的粒度:
属性 | 类型 | 描述 |
---|---|---|
value | String | 可选的限定描述符,指定使用的事务管理器 |
porpagation | enum: Propagation | 可选的事务传播行为设置 |
isolation | enum: Isolation | 可选的事务隔离级别设置 |
readOnly | boolean | 读写或只读事务,默认读写 |
timeout | int (in seconds granularity) | 事务超时时间设置 |
rollbackFor | Class对象数组,必须继承自Throwable | 导致事务回滚的异常类数组 |
rollbackForClassName | 类名数组,必须继承自Throwable | 导致事务回滚的异常类名字数组 |
noRollbackFor | Class对象数组,必须继承自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:
如果当前存在一个事务,则加入当前事务。如果不存在任何事务,则创建一个新的事务。他可能会两个事务合并成一个,或外部没有事务时自己创建一个事务。一般作为事务默认的传播行为。
Comments | NOTHING