SpringBoot - 事务处理
事务介绍
是一组操作的集合,它是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败
Spring 事务管理:
- 注解: @Transactional
- 位置:业务层的方法上、类上、接口上
- 作用:将当前方法交给spring 进行事务管理,方法执行前,开始事务。成功执行完毕,提交事务,出现异常,回滚事务
引入案例
package com.chuangzhou.serivce.impl;
import com.chuangzhou.mapper.DeptMapper;
import com.chuangzhou.mapper.EmpMapper;
import com.chuangzhou.pojo.Dept;
import com.chuangzhou.pojo.Emp;
import com.chuangzhou.serivce.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Autowired
private EmpMapper empMapper;
//删除部门信息
@Transactional
@Override
public void delete(Integer id) {
deptMapper.deleteById(id); // 删除部门
int i = 1/ 0; //遇到异常后,部门被删除,但是部门下的员工无法删除
empMapper.deleteByDeptId(id);
}
}
application.yml打开日志:
logging:
level:
org.springframework.jdbc.support.JdbcTransactionManager: debug
执行删除部门后可以看到事务回滚日志:
事务进阶 - rollbackFor
@Transactional
@Override
public void delete(Integer id) throws Exception {
deptMapper.deleteById(id); // 删除部门
if(true){
throw new Exception("出错了......");
}
empMapper.deleteByDeptId(id);
}
执行以上代码后会发现事务没有回滚,部门被删除了,但是部门下的员工却没有被删除。
原因:
@Trancaction注解:默认情况下只有出现RunTimeException 才回滚异常。
解决:
rollbackFor属性用于控制出现何种异常类型,回滚事务
@Transactional(rollbackFor = {Exception.class}) //所有的异常都会回滚
@Override
public void delete(Integer id) throws Exception {
deptMapper.deleteById(id); // 删除部门
if(true){
throw new Exception("出错了......");
}
empMapper.deleteByDeptId(id);
}
成功回滚:
事务进阶 - propagation
背景:
- 事务的传播行为:指的就时当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制
需求:删除员工时不管删除成功还是失败都将日志信息记录到数据库
引入案例:
deptServiceImpl 逻辑:
@Transactional
@Override
public void delete(Integer id) throws Exception {
try {
deptMapper.deleteById(id); // 删除部门
int i = 1/0;
empMapper.deleteByDeptId(id);
} finally {
// 不管删除部门信息的操作是否成功 都需要将日志信息记录到数据库
DeptLog deptLog = new DeptLog();
deptLog.setCreateTime(LocalDateTime.now());
deptLog.setDescription("执行了删除部门操作");
deptLogService.insert(deptLog);
}
}
DeptLogImpl : 注意的是insert 方法也加入了 事务管理
package com.chuangzhou.serivce.impl;
import com.chuangzhou.mapper.DeptLogMapper;
import com.chuangzhou.pojo.DeptLog;
import com.chuangzhou.serivce.DeptLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DeptLogImpl implements DeptLogService {
@Autowired
private DeptLogMapper deptLogMapper;
@Transactional
@Override
public void insert(DeptLog deptLog) {
deptLogMapper.insert(deptLog);
}
}
删除部分后发现日志信息并没有插入到数据库:
原因:
@Transaction 默认的传播行为:REQUIRE:有事务则加入,无事务创建新的事物
解决:
修改事务的默认值: @Transactional(propagation = Propagation.REQUIRES_NEW)
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void insert(DeptLog deptLog) {
deptLogMapper.insert(deptLog);
}
数据库也插入成功:
事务传播行为的可选值:
场景:
- REQUIRED:大部分情况下都是用该传播行为即可。
- REQUIRES_NEW: 当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功
本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/17659956.html