【Spring从入门到实战】第 6 讲:SpringBoot 的事务管理

本文介绍了Spring中的事务管理,包括编程式事务的TransactionTemplate和TransactionManager实现,以及声明式事务@Transactional的使用和工作原理。文章强调了事务在数据库安全性中的重要性,并对比了编程式事务(如手动挡车)和声明式事务(如自动挡车)的灵活性与简便性。此外,还讨论了事务属性和AOP在实现事务管理中的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文已收录于专栏
🌲《Spring从入门到实战》🌲

专栏前言

   大家好,我是执梗。本专栏将从Spring入门开始讲起,详细讲解各类配置的使用以及原因,到使用SpringBoot进行开发实战,旨在记录学习生活的同时也希望能帮到大家,如果对您能有所帮助,还望能点赞关注该专栏,对于专栏内容有错还望您可以及时指点,非常感谢大家 🌹。

1.为什么需要事务?

   事务这东西大家在学习Mysql时肯定就已经接触过了,我们先回顾其定义:将一组操作封装成一个原子操作,要么全部成功,要么全部失败。
可以说事务是数据库数据安全的保障,在以前Mysql中我们事务有三个重要的操作:

    1. start transaction 开启事务
    1. commit 提交事务
    1. rollback 回滚事务

2.Spring 中的事务

   Spring中支持两种事务编程模型,一种叫做编程式事务,一种叫声明式事务。下面我们会主动来讲他们两个的实现以及区别,其实大家可以将两者类比为手动挡的车和自动挡的车的区别。
  这里有一个非常重要的一点,Spring对事务的支持是基于你的数据库是否支持事务。 如果你的数据库引擎是InnoDB,那么你的数据库是支持事务的,如果是MyISAM的话那么就不支持事务。

3.编程式事务

   编程式事务好比与我们的手动挡的车,一切操作都需要程序员通过代码去手动实现。它的操作步骤和Mysql是一样的,分别是开启事务、提交事务、回滚事务。
SpringBoot中实现编程式事务又要两种方法:

  • 1.使用 TransactionTemplate 对象实现编程式事务
  • 2.使用 TransactionManager 对象实现编程式事务

学习之前大家须知平时我们并不会使用编程式事务,因为它操作比较麻烦,大家通过下面的代码实现也是可以看出来的,但其优点是比较灵活

3.1使用 TransactionTemplate 实现事务

@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private UserService userService;

    @RequestMapping("/add")
    public int add(User user) {
        //非空校验
        if (user == null || !StringUtils.hasLength(user.getUsername()) ||
                StringUtils.hasLength(user.getPassword())) return 0;
        // 开启并执行事务
        return transactionTemplate.execute(status -> {
            int result = 0;
            try {
            	//业务代码
                result = userService.add(user);
            } catch (Exception e) {
                //若产生异常则回滚
                status.setRollbackOnly();
            }
            return result;
        });
    }
}

3.2使用 TransactionManager 实现事务


@RestController
public class UserController {
  @Resource
  private UserService userService;
  // JDBC 事务管理器
  @Resource
  private DataSourceTransactionManager dataSourceTransactionManager;
  // 定义事务属性
  @Resource
  private TransactionDefinition transactionDefinition;
  @RequestMapping("/add")
  public int add(User user) {
    //非空校验
        if (user == null || !StringUtils.hasLength(user.getUsername()) ||
                StringUtils.hasLength(user.getPassword())) return 0;
    // 开启事务
    TransactionStatus transactionStatus =
dataSourceTransactionManager
       .getTransaction(transactionDefinition);
		try{
		// 插⼊数据库
    	int result = userService.add(user);
   		 // 提交事务
    	dataSourceTransactionManager.commit(transactionStatus);
		}catch{
		//  回滚事务
    	dataSourceTransactionManager.rollback(transactionStatus);
		}    
    return result;
   }
}

这里注意到一个对象为transactionDefinition,它是管理我们的事务属性的。
   那么什么是事务属性呢?
   事务属性包含5个方面:

  • 1.隔离级别
  • 2.传播行为
  • 3.回滚规则
  • 4.是否超时
  • 5.事务超时

transactionDefinition中就定义了以上这些基本的事务属性的常量,大家可以自行深入了解,当然我们也可以使用对应的方法去设置这些值。

4.声明式事务

   声明式事务的实现就非常简单了,只需要在方法或者类上加上注解 @Transactional 即可。这样在方法执行前,它将会自动开始事务,在结束后自动提交事务,若中途发生异常,会自动回滚事务。下面是代码的实现:

@RequestMapping("/add")
    @Transactional
    public int add(User user) {
        //非空校验
        if (user == null || !StringUtils.hasLength(user.getUsername()) ||
                StringUtils.hasLength(user.getPassword())) return 0;
        int result = userService.add(user);
        return result;
    }

@Transactional注解中可以添加许多参数,每个参数的含义如下,这里就包含了设置事务属性的方法
在这里插入图片描述
   当然我们前面提了@Transactional也是可以加在类上的,当加到类上时,其作用是为该类中所有public方法开启事务。
  还有一点需要注意的是,在声明式事务中,如果产生异常且该异常被捕获了,此时是不会进行回滚的。解决方法有两种:

  • 1.将捕获的异常重新抛出去
@RequestMapping("/add")
@Transactional(isolation = Isolation.SERIALIZABLE)
public int add(User user) {
  // 插⼊数据库
  int result = userService.add(user);
  try {
    // 执⾏了异常代码(0不能做除数)
    int i = 10 / 0;
 } catch (Exception e) {
    System.out.println(e.getMessage());
    // 将异常重新抛出去
    throw e;
 }
  return result;
}
  • 2.手动进行回滚,在方法中使用TransactionAspectSupport.currentTransactionStatus()获取事务后,调用setRollbackOnly回滚方法手动回滚。
@RequestMapping("/add")
@Transactional(isolation = Isolation.SERIALIZABLE)
public int save(User user) {
  // 插⼊数据库
  int result = userService.add(user);
  try {
    // 执⾏了异常代码(0不能做除数)
    int i = 10 / 0;
 } catch (Exception e) {
    System.out.println(e.getMessage());
    // ⼿动回滚事务
 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
 }
  return result;
}

5. @Transactional 工作原理

   @Transactional是基于AOP进行实现的,而AOP又是通过动态代理进行实现的。同理可知如果目标对象实现了接口则使用Java自带的动态代理,否则使用CGLIB动态代理。
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

执 梗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值