0
点赞
收藏
分享

微信扫一扫

【SpringBoot】事务的使用(编程式、声明式)及 @Transactional 工作原理、失效处理

@TOC

回顾 事务

  • 事务的本质就是某个操作要么都成功, 要么都失败
  • 事务在项目开发中十分重要, 涉及到数据一致性和完整性问题, 不能马虎
  • 事务的ACID原则
  1. 原子性
  2. 一致性
  3. 隔离性, 多个业务可能操作同一个资源, 防止数据损坏
  4. 持久性, 事务一旦发生, 无论系统发生什么问题, 结果都不会再被影响, 被持久的写到存储器中

Spring 中事务的实现

Spring 中的事务操作分为两类:

  1. ⼿动操作事务
  2. 声明式⾃动提交事务

在开始讲解它们之前,咱们先来回顾事务在 MySQL 中是如何使⽤的?

MySQL 中的事务使⽤(回顾)

事务在 MySQL 有 3 个重要的操作:

  1. 开启事务
  2. 提交事务
  3. 回滚事务

它们对应的操作命令如下:

-- 开启事务
start transaction;
-- 业务执⾏

-- 提交事务
commit;

-- 回滚事务
rollback;

Spring 编程式事务(手动操作)

Spring ⼿动操作事务和上⾯ MySQL 操作事务类似,它也是有 3 个重要操作步骤:

  1. 开启事务(获取事务)getTransaction
  2. 提交事务 commit
  3. 回滚事务 rollback

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

观察它们的执⾏区别:

image-20220713113955918

  • 开启事务时,如果代码运行时发生异常会会进行回滚
  • 没有开启事务时,如果代码运行时发生异常不会进行回滚,代码依然会进行操作

@Transactional 作⽤范围

@Transactional 可以⽤来修饰⽅法或类:

  1. 修饰⽅法时:需要注意只能应⽤到 public ⽅法上否则不⽣效。推荐此种⽤法。
  2. 修饰类时:表明该注解对该类中所有的 public ⽅法都⽣效

@Transactional 参数说明

image-20220713153427937

注意事项

@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:将捕获异常重新抛出

对于捕获的异常,事务是会⾃动回滚的

image-20220713165842088

因此解决⽅案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 就可以实现回滚了

image-20220713165905990

具体实现代码如下:

@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 实现思路预览:

image-20220713164534896

@Transactional 具体执⾏细节如下图所示:

image-20220713164538860

举报

相关推荐

0 条评论