Spring 中事务的实现有两种方法:
Spring 手动操作事务, 一共三个重要步骤: ①开启事务,②提交事务,③回滚事务
@RestController
public class UserController2 {
@Resource
private UserService userService;
// JDBC 事务管理器
@Resource
private DataSourceTransactionManager dataSourceTransactionManager;
// 定义事务属性
@Resource
private TransactionDefinition transactionDefinition;
@RequestMapping("/save")
public Object save(User user) {
// 1. 开启事务
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
// 插入数据库
int result = userService.save(user);
// 2. 提交事务
dataSourceTransactionManager.commit(transactionStatus);
// 3. 回滚事务
dataSourceTransactionManager.rollback(transactionStatus);
return result;
}
}
在方法上添加 @Transactional
注解就可以实现了
无需手动开启事务和提交事务, 进入方法时自动开启事务, 方法执行完会自动提交事务, 如果中途发生了没有处理的异常会自动回滚事务
@RestController
public class UserController2 {
@Resource
private UserService userService;
@RequestMapping("/save")
@Transactional
public Object save(User user) {
int result = userService.save(user);
return result;
}
}
@Transactional 可以用来修饰方法或类:
public
方法上, 否则不生效.public
方法都生效.参数 | 作用 |
---|---|
value | 当配置了多个事务管理器时, 可以使用该属性指定选择哪个事务管理器 |
transactionManager | 当配置了多个事务管理器时, 可以使用该属性指定选择哪个事务管理器. |
propagation | 事务的传播行为. 默认为 Propagation.REQUIRED |
isolation | 事务的隔离级别. 默认为 Isolation.DAEFAULT |
timeout | 事务的超时事件. 默认值为-1, 如果超过该时间限制但事务还没有完成, 则自动回滚事务. |
readOnly | 指定事务是否只读事务. 默认为 false. 为了忽略那些不需要事务的方法, 比如读取数据, 可以设置为 read-only 为 true |
rollbackFor | 用于指定能够触发事务回滚的异常类型, 可以指定多个异常类型 |
rollbackForClassName | 用于指定能够触发事务回滚的异常类型, 可以指定多个异常类型 |
noRollbackFor | 抛出指定的异常类型, 不回滚事务, 也可以指定多个异常类型 |
noRollbackForClassName | 抛出指定的异常类型, 不回滚事务, 也可以指定多个异常类型 |
当前的代码:
@RequestMapping("/save")
@Transactional
public Object save(User user) {
int result = userService.save(user);
try {
int a = 10/0;
}catch (Exception e) {
e.printStackTrace();
}
return result;
}
当前数据库表中的内容:
运行之后表中的内容
此时发现, 出现异常的情况, 不会发生事务回滚
@RequestMapping("/save")
@Transactional
public Object save(User user) {
int result = userService.save(user);
try {
int a = 10/0;
}catch (Exception e) {
e.printStackTrace();
throw e;
}
return result;
}
此时数据库中也不会有数据
使用 TransctionAspectSupport.currentTransactionStatus() 可以得到当前事务
然后使用 setRollbackOnly 就可以实现回滚.
@RequestMapping("/save")
@Transactional
public Object save(User user) {
int result = userService.save(user);
try {
int a = 10/0;
}catch (Exception e) {
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return result;
}
Isolation.DEFAULT
: 以连接的数据库的事务隔离级别为主Isolation.READ_UNCOMMITTED
: 读未提交, 可以读取到未提交的事务, 存在脏读Isolation.READ_COMMITTED
: 读已提交, 只能读取到已经提交的事务, 解决了脏读, 但存在不可重复读Isolation.REPEATABLE_READ
: 可重复读, 解决了不可重复读, 但存在幻读Isolation.SERIALIZABLE
: 串行化, 可以解决所有并发问题, 但性能低只需要通过 @Transactional 中的 isolation 属性进行设置即可
Spring 事务传播机制定义了多个包含了事务的方法, 相互调用时, 事务是如何在这些方法间进行传递的
事务隔离级别 保证多个并发事务执行的可控性
事务传播机制 保证一个事务在多个调用方法间的可控性
Spring 事务的传播机制包含以下 7 种 :
Propagation.REQUIRED
: 默认的事务传播级别, 它表示如果当前存在事务, 则加入该事务; 如果当前没有事务, 则创建一个新的事务.Propagation.SUPPORTS
: 如果当前存在事务, 则加入该事务; 如果当前没有事务, 则以非事务的方式继续运行.Propagation.MANDATORY
: 如果当前存在事务, 则加入该事务; 如果当前没有事务, 则抛出异常.Propagation.REQUIRES_NEW
: 表示创建一个新的事务, 如果当前存在事务, 则把当前事务挂起.Propagation.NOT_SUPPORTED
: 以非事务方式运行, 如果当前存在事务, 则把当前事务挂起.Propagation.NEVER
: 以非事务方式运行, 如果当前存在事务, 则抛出异常.Propagation.NESTED
: 如果当前存在事务, 则创建一个事务作为当前事务的嵌套事务来运行; 如果不存在事务, 则创建一个新的事务.@RestController
public class UserController2 {
@Resource
private UserService userService;
@Resource
private LogService logService;
@RequestMapping("/save")
@Transactional(propagation = Propagation.REQUIRED)
public Object save(User user) {
int result = userService.save(user);
logService.saveLog("用户插入: " + user.getUsername());
return result;
}
}
UserService 代码 和 LogService 代码
运行结果:
发现 LogSerivice 出错, 导致 LogService操作回滚, 也导致 UserService 报错
修改 UserService
和 LogService
为 Propagation.REQUIRES_NEW
运行结果:
User表中插入成功, Log表中插入失败.
修改 LogService
为 Propagation=Propagation.NEVER
将 log的代码移到前面
@RequestMapping("/save")
@Transactional
public Object save(User user) {
logService.saveLog("用户插入: " + user.getUsername());
int result = userService.save(user);
return result;
}
运行结果:
执行到 logService.saveLog 这段就报错. 就不会继续往下走了.
修改 LogService
和 UserService
代码为 Propagation.NESTED
运行结果:
用户表和日志表都没有添加任何的数据
将嵌套事务中的 LogService 中进行当前事务的回滚操作.
运行结果:
User表操作成功, Log表操作失败.
还是在 LogService 中 执行回滚操作.
运行结果:
此时 User表插入数据失败, Log表插入数据也失败.
嵌套事务 (NESTED) 和 加入事务 (REQUIRED) 的区别
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://wangzhi430.blog.csdn.net/article/details/125300581
内容来源于网络,如有侵权,请联系作者删除!