Spring 事务传播机制定义了多个包含了事务的⽅法,相互调⽤时,事务是如何在这些⽅法间进⾏传递的。
事务隔离级别是保证多个并发事务执⾏的可控性的(稳定性的),⽽事务传播机制是保证⼀个事务在多个调⽤⽅法间的可控性的(稳定性的)。
举个栗子:
比如新冠病毒,它有不同的隔离⽅式(酒店隔离还是居家隔离),是为了保证疫情可控,然⽽在每个⼈的隔离过程中,会有很多个执⾏的环节,⽐如酒店隔离,需要负责⼈员运送、物品运送、消杀原⽣活区域、定时核算检查和定时送餐等很多环节,⽽事务传播机制就是保证⼀个事务在传递过程中是可靠性的,回到本身案例中就是保证每个⼈在隔离的过程中可控的。
事务隔离级别解决的是多个事务同时调⽤⼀个数据库的问题,如下图:
⽽事务传播机制解决的是⼀个事务在多个节点(⽅法)中传递的问题,如下图所示:
方法 1 调用 方法 2, 方法 2 调用方法 3:
Spring 事务传播机制包含以下 7 种:
以上 7 种传播⾏为,可以根据是否⽀持当前事务分为以下 3 类:
以情侣关系为例来理解以上分类:
先开启事务先成功插⼊⼀条⽤户数据,然后再执⾏⽇志报错,⽽在⽇志报错是发⽣了异常,观察 propagation = Propagation.REQUIRED 的执⾏结果。
controller 层,传播机制为 REQUIRED,先调用保存用户,再调用保存 日志
@RestController
public class UserController {
@Resource
private UserService userService;
@Resource
private LogService logService;
@RequestMapping("/save")
@Transactional(propagation = Propagation.REQUIRED)
public Object save(User user) {
// 插⼊⽤户操作
userService.save(user);
// 插⼊⽇志
logService.saveLog("⽤户插⼊:" + user.getUsername());
return true;
}
}
UserService ,传播机制为 REQUIRED,正常保存
@Service
public class UserService {
@Resource
private UserMapper userMapper;
@Transactional(propagation = Propagation.REQUIRED)
public int save(User user) {
System.out.println("执⾏ save ⽅法.");
return userMapper.save(user);
}
}
LogService ,传播机制为 REQUIRED,抛异常,注意异常一定要捕获
@Service
public class LogService {
@Resource
private LogMapper logMapper;
@Transactional(propagation = Propagation.REQUIRED)
public int saveLog(String content) {
int result = logMapper.saveLog(content);
// 出现异常
try {
int i = 10 / 0;
} catch (Exception e) {
// 一定要捕捉异常
// 然后手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return result;
}
}
执⾏结果:用户表和日志表都没有插⼊任何数据。
UserController 类中的代码不变,将添加⽇志的⽅法修改为 REQUIRES_NEW 不⽀持当前事务,重新创建事务,观察执⾏结果:
controller 层,传播机制为 REQUIRED,先调用保存用户,再调用保存 日志
@RestController
public class UserController {
@Resource
private UserService userService;
@Resource
private LogService logService;
@RequestMapping("/save")
@Transactional(propagation = Propagation.REQUIRED)
public Object save(User user) {
// 插⼊⽤户操作
userService.save(user);
// 插⼊⽇志
logService.saveLog("⽤户插⼊:" + user.getUsername());
return true;
}
}
UserService ,传播机制为 REQUIRES_NEW,正常保存
@Service
public class UserService {
@Resource
private UserMapper userMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int save(User user) {
System.out.println("执⾏ save ⽅法.");
return userMapper.save(user);
}
}
LogService ,传播机制为 REQUIRES_NEW,抛异常, 注意异常一定要捕获
@Service
public class LogService {
@Resource
private LogMapper logMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int saveLog(String content) {
int result = logMapper.saveLog(content);
// 出现异常
try {
int i = 10 / 0;
} catch (Exception e) {
// 一定要捕捉异常
// 然后手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return result;
}
}
程序执⾏结果:User 表中成功插⼊了数据,Log 表执⾏失败,但没影响 UserController 中的事务。
controller 层,传播机制为 REQUIRED,只调用保存用户
@RestController
public class UserController {
@Resource
private UserService userService;
@RequestMapping("/save")
@Transactional(propagation = Propagation.REQUIRED)
public Object save(User user) {
// 插⼊⽤户操作
userService.save(user);
return true;
}
}
UserService ,传播机制为 NEVER,正常保存
@Service
public class UserService {
@Resource
private UserMapper userMapper;
@Transactional(propagation = Propagation.NEVER)
public int save(User user) {
System.out.println("执⾏ save ⽅法.");
return userMapper.save(user);
}
}
程序执⾏报错,⽤户表未添加任何数据。
controller 层,传播机制为 REQUIRED/NESTED/或者不写参数都行,调用保存用户
@RestController
public class UserController {
@Resource
private UserService userService;
@RequestMapping("/save")
@Transactional(propagation = Propagation.REQUIRED)
public Object save(User user) {
// 插⼊⽤户操作
userService.save(user);
return true;
}
}
UserService ,传播机制为 NESTED ,正常保存
@Service
public class UserService {
@Resource
private UserMapper userMapper;
@Resource
private LogService logService;
@Transactional(propagation = Propagation.NESTED)
public int save(User user) {
int result = userMapper.save(user);
System.out.println("执⾏ save ⽅法.");
// 调用插入插⼊⽇志的方法
logService.saveLog("⽤户插⼊:" + user.getUsername());
return result;
}
}
LogService ,传播机制为 NESTED ,抛异常, 注意异常一定要捕获
@Service
public class LogService {
@Resource
private LogMapper logMapper;
@Transactional(propagation = Propagation.NESTED)
public int saveLog(String content) {
int result = logMapper.saveLog(content);
// 出现异常
try {
int i = 10 / 0;
} catch (Exception e) {
// 一定要捕捉异常
// 然后手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return result;
}
}
最终程序的执⾏结果:
⽤户表中数据添加成功,⽇志表中没有添加任何数据,Log 中的事务已经回滚,但是嵌套事务不会回滚嵌套之前的事务,也就是说嵌套事务可以实现部分事务回滚。
嵌套事务之所以能够实现部分事务的回滚,是因为事务中有⼀个保存点(savepoint)的概念,嵌套事务进⼊之后相当于新建了⼀个保存点,⽽回滚时只回滚到当前保存点,因此之前的事务是不受影响的。
嵌套事务(NESTED)和加⼊事务(REQUIRED )的区别:
嵌套事务(NESTED)和新建事务(REQUIRE_NEW )的区别:
注意:
好啦! 以上就是对 Spring 事务传播机制 的讲解,希望能帮到你 !
评论区欢迎指正 !