SpringBoot中事务处理方式(编程声明)和@Transactional注解机制及失效解决方法如何实现?

2026-05-29 11:523阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1621个文字,预计阅读时间需要7分钟。

SpringBoot中事务处理方式(编程/声明)和@Transactional注解机制及失效解决方法如何实现?

@TOC回顾:事务的本质事务的本质是确保一系列操作要么全部成功,要么全部失败。在项目开发中,事务的重要性体现在以下几个方面:

1. 十分重要:事务在项目开发中占据十份重要的地位。

2.数据一致性:事务涉及到数据的一致性和完整性问题。

3.ACID原则:事务遵循ACID原则,即原子性、一致性、隔离性和持久性。

4.原子性:事务中的操作要么全部完成,要么全部不做。

5.一致性:事务确保数据库状态从一个一致性状态转换到另一个一致性状态。

6.隔离性:事务在执行过程中不受外界干扰,保证数据的一致性。

7.持久性:一旦事务提交,其结果将永久保存在数据库中。

@TOC


回顾 事务

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

  • Spring 中事务的实现

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

  • ⼿动操作事务
  • 声明式⾃动提交事务
  • 在开始讲解它们之前,咱们先来回顾事务在 MySQL 中是如何使⽤的?


    MySQL 中的事务使⽤(回顾)

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

  • 开启事务
  • 提交事务
  • 回滚事务
  • 它们对应的操作命令如下:

    -- 开启事务 start transaction; -- 业务执⾏ -- 提交事务 commit; -- 回滚事务 rollback;

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

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

  • 开启事务(获取事务)getTransaction
  • 提交事务 commit
  • 回滚事务 rollback
  • SpringBoot 内置了两个对象:

    DataSourceTransactionManager ⽤来 获取事务(开启事务)、提交或 回滚事务

    SpringBoot中事务处理方式(编程/声明)和@Transactional注解机制及失效解决方法如何实现?

    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 可以⽤来修饰⽅法或类:

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

  • @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 具体执⾏细节如下图所示:


    本文共计1621个文字,预计阅读时间需要7分钟。

    SpringBoot中事务处理方式(编程/声明)和@Transactional注解机制及失效解决方法如何实现?

    @TOC回顾:事务的本质事务的本质是确保一系列操作要么全部成功,要么全部失败。在项目开发中,事务的重要性体现在以下几个方面:

    1. 十分重要:事务在项目开发中占据十份重要的地位。

    2.数据一致性:事务涉及到数据的一致性和完整性问题。

    3.ACID原则:事务遵循ACID原则,即原子性、一致性、隔离性和持久性。

    4.原子性:事务中的操作要么全部完成,要么全部不做。

    5.一致性:事务确保数据库状态从一个一致性状态转换到另一个一致性状态。

    6.隔离性:事务在执行过程中不受外界干扰,保证数据的一致性。

    7.持久性:一旦事务提交,其结果将永久保存在数据库中。

    @TOC


    回顾 事务

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

  • Spring 中事务的实现

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

  • ⼿动操作事务
  • 声明式⾃动提交事务
  • 在开始讲解它们之前,咱们先来回顾事务在 MySQL 中是如何使⽤的?


    MySQL 中的事务使⽤(回顾)

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

  • 开启事务
  • 提交事务
  • 回滚事务
  • 它们对应的操作命令如下:

    -- 开启事务 start transaction; -- 业务执⾏ -- 提交事务 commit; -- 回滚事务 rollback;

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

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

  • 开启事务(获取事务)getTransaction
  • 提交事务 commit
  • 回滚事务 rollback
  • SpringBoot 内置了两个对象:

    DataSourceTransactionManager ⽤来 获取事务(开启事务)、提交或 回滚事务

    SpringBoot中事务处理方式(编程/声明)和@Transactional注解机制及失效解决方法如何实现?

    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 可以⽤来修饰⽅法或类:

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

  • @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 具体执⾏细节如下图所示: