@TOC
回顾 事务
- 事务的本质就是某个操作要么都成功, 要么都失败
- 事务在项目开发中十分重要, 涉及到数据一致性和完整性问题, 不能马虎
- 事务的ACID原则
Spring 中事务的实现
Spring 中的事务操作分为两类:
在开始讲解它们之前,咱们先来回顾事务在 MySQL 中是如何使⽤的?
MySQL 中的事务使⽤(回顾)
事务在 MySQL 有 3 个重要的操作:
它们对应的操作命令如下:
-- 开启事务 start transaction; -- 业务执⾏ -- 提交事务 commit; -- 回滚事务 rollback;Spring 编程式事务(手动操作)
Spring ⼿动操作事务和上⾯ MySQL 操作事务类似,它也是有 3 个重要操作步骤:
SpringBoot 内置了两个对象:
DataSourceTransactionManager ⽤来 获取事务(开启事务)、提交或 回滚事务
TransactionDefinition 是 事务的属性
获取事务的时候需要将 TransactionDefinition 传递进去从⽽获得⼀个事务 TransactionStatus
实现代码如下:
@RestController public class UserController { @Resource private UserService userService; // 注入 JDBC 事务管理器 @Resource private DataSourceTransactionManager dataSourceTransactionManager; // 注入 定义事务属性 @Resource private TransactionDefinition transactionDefinition; @RequestMapping("/sava") public Object save(User user) { // 开启事务 TransactionStatus transactionStatus = dataSourceTransactionManager .getTransaction(transactionDefinition); // 插⼊数据库 int result = userService.save(user); // 提交事务 dataSourceTransactionManager.commit(transactionStatus); // 回滚事务 dataSourceTransactionManager.rollback(transactionStatus); return result; } }从上述代码可以看出,以上代码虽然可以实现事务,但操作也很繁琐,有没有更简单的实现⽅法呢?请 看下⾯声明式事务。
Spring 声明式事务(自动事务)
声明式事务的实现很简单,只需要在需要的⽅法上添加 @Transactional 注解就可以实现了
⽆需⼿动 开启事务和提交事务,进⼊⽅法时⾃动开启事务,⽅法执⾏完会⾃动提交事务,如果中途发⽣了没有处理的异常会⾃动回滚事务
具体实现代码如下:
@RequestMapping("/save") @Transactional //开启事务 public Object save(User user) { int result = userService.save(user); return result; }接下⾥使⽤以下代码,分别设置 @Transactional 注解和不设置 @Transactional
观察它们的执⾏区别:
- 开启事务时,如果代码运行时发生异常会会进行回滚
- 没有开启事务时,如果代码运行时发生异常不会进行回滚,代码依然会进行操作
@Transactional 作⽤范围
@Transactional 可以⽤来修饰⽅法或类:
@Transactional 参数说明
注意事项
@Transactional 在异常被捕获的情况下,不会进⾏事务⾃动回滚。
验证以下代码是否会发⽣事务回滚:
@RestController public class UserController { @Resource private UserService userService; @RequestMapping("/save") @Transactional public Object save(User user) { // 插⼊数据库 int result = userService.save(user); try { // 执⾏了异常代码(0不能做除数) int i = 10 / 0; } catch (Exception e) { System.out.println(e.getMessage()); } return result; } }事务不会自动回滚解决⽅案
解决⽅案1:将捕获异常重新抛出
对于捕获的异常,事务是会⾃动回滚的
因此解决⽅案1就是可以将异常重新抛出,具体实 现如下:
@RequestMapping("/save") @Transactional(isolation = Isolation.SERIALIZABLE) public Object save(User user) { // 插⼊数据库 int result = userService.save(user); try { // 执⾏了异常代码(0不能做除数) int i = 10 / 0; } catch (Exception e) { System.out.println(e.getMessage()); throw e; // 将异常重新抛出去 } return result; }解决⽅案2:手动回滚事务
在⽅法中使⽤ TransactionAspectSupport.currentTransactionStatus( ) 可 以得到当前的事务
设置回滚⽅法 setRollbackOnly 就可以实现回滚了
具体实现代码如下:
@RequestMapping("/save") @Transactional(isolation = Isolation.SERIALIZABLE) public Object save(User user) { // 插⼊数据库 int result = userService.save(user); try { // 执⾏了异常代码(0不能做除数) int i = 10 / 0; } catch (Exception e) { System.out.println(e.getMessage()); // ⼿动回滚事务 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return result; }@Transactional ⼯作原理
@Transactional 是基于 AOP 实现的,AOP ⼜是使⽤动态代理实现的。
如果⽬标对象实现了接⼝,默认 情况下会采⽤ JDK 的动态代理
如果⽬标对象没有实现了接⼝,会使⽤ CGLIB 动态代理。
@Transactional 在开始执⾏业务之前,通过代理先开启事务,在执⾏成功之后再提交事务。如果中途遇 到的异常,则回滚事务。
@Transactional 实现思路预览:
@Transactional 具体执⾏细节如下图所示:
【文章原创作者:高防cdn http://www.juniucdn.com欢迎留下您的宝贵建议】