什么是事务
事务是指在程序定义的一个操作序列。所有操作要么全部执行成功,要么认为全部执行失败,并且撤销所有操作已经做出的更改。
事务的四个特性(ACID)
- 原子性(Atomicity) : 将所有的操作当成是一个操作来执行,全部成功则成功,执行中如果出错,则回滚当前所有操作
- 一致性(Consistency) : 程序运行后要求数据保持一致。比如我借给了朋友100块钱,那朋友手里就该多了100块钱,而我手里就少了100块钱。
- 隔离性(Isolation) : 多个事务之间要相互隔离,不能相互干扰
- 持久性(Durability) : 事务执行结束后,对数据的更改是永久性的
示例代码(不开启事务)
@Test
void ceshi(){
Hotel hotel = new Hotel();
hotel.setId(36934L);
hotel.setPrice(336);
hotelService.updateById(hotel);
//制造异常
int num = 1/0;
...
}
// 执行前
{"id":36934,"price":400}
// 执行后
{"id":36934,"price":336}
当程序运行到1/0这一行,就会报错,并且由于没有开启事务,所以之前的修改也会生效,等于成功了一半失败了一半,导致数据前后不一致,这样很容易使数据变得混乱。假如现在有一个支付业务,用户已经支付成功了,订单也已被修改成已支付的状态,但是由于程序在运行过程中出了个错,导致商品的已收款金额没有更新,这显然是一个事故。
示例代码(开启事务)
@Test
@Transactional //开启事务
void ceshi(){
Hotel hotel = new Hotel();
hotel.setId(36934L);
hotel.setPrice(336);
hotelService.updateById(hotel);
//制造异常
int num = 1/0;
}
// 执行前
{"id":36934,"price":400}
// 执行后
{"id":36934,"price":400}
当程序运行到1/0这一行,程序虽然会报错,但是由于开启了事务,所以事务管理器会帮我们回滚当前事务中的所有更新操作。假如现在有一个支付业务,用户已经支付成功了,订单也已被修改成已支付的状态,但是由于程序在运行过程中出了个错,所以事务管理器会帮我们回滚修改订单状态的操作。
Spring事务实现原理
网上有很多文章说需要在启动类或配置类中加入 @EnableTransactionManagement 注解才能开启事务,其实不需要,SpringBoot的自动装配会帮我们完成这个操作,并且SpringBoot还会帮我们创建一个拦截器 TransactionInterceptor ,帮助我们拦截执行的所有被 @Transactional 注解的方法。
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
Method var10001 = invocation.getMethod();
invocation.getClass();
//调用父类的方法
return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);
}
在程序运行到TransactionInterceptor时,在invoke方法中会调用父类的invokeWithinTransaction方法,该方法内包含一个事物管理器,在该方法内会先开启事物,紧接着执行代理方法,最后根据执行结果,事物管理器会自动执行提交或回滚。
事务管理器PlatformTransactionManager完成了具体的数据库事务操作,TransactionInterceptor完成了基于动态代理的面向切面过程。AOP+事务管理器实现了Spring事务的核心功能。