Spring框架学习系列《Spring框架学习一从设计思想到核心架构全面认识Spring》《Spring框架学习二IOC核心原理解析为什么Autowired可以自动注入》《Spring框架学习三Spring Bean生命周期详解》《Spring框架学习四Spring AOP动态代理实现原理》《Spring框架学习五Spring MVC请求处理流程解析》《Spring框架学习六Spring事务实现原理》《Spring框架学习七Spring Boot自动配置原理》《Spring框架学习八Spring源码整体流程总结》一、前言在企业级 Java 开发中事务是非常重要的一部分。例如银行转账业务public void transfer(){ //账户A扣钱 //账户B加钱 }这个业务必须满足A扣钱成功B加钱成功如果A扣钱成功但是B加钱失败。那么数据就会出现错误。因此需要事务保证一组数据库操作要么全部成功要么全部失败。在 Spring 中我们经常使用Transactional public void transfer(){ }只需要添加一个注解Spring 就可以自动完成开启事务提交事务异常回滚那么Transactional背后到底发生了什么本文将从事务基础、Spring事务模型、AOP实现原理以及源码流程几个方面进行分析。二、什么是事务事务Transaction简单理解一个不可分割的数据库操作单元。事务具有四个基本特性ACID1. 原子性Atomicity事务中的操作要么全部完成,要么全部不完成。例如转账扣钱 加钱不能只执行一半。2. 一致性Consistency事务执行前后数据必须保持正确。例如账户总金额A账户 B账户 固定值不会因为失败导致数据错误。3. 隔离性Isolation多个事务同时执行时互相不影响。例如两个用户同时修改订单。4. 持久性Durability事务提交后数据永久保存。三、传统事务处理方式在没有 Spring 之前开发者需要手动控制事务。例如Connection conn dataSource.getConnection(); try{ conn.setAutoCommit(false); //业务代码 conn.commit(); }catch(Exception e){ conn.rollback(); }问题大量重复代码业务代码和事务代码混合容易遗漏例如每个Service方法都需要写begin(); commit(); rollback();维护成本非常高。四、Spring事务解决方案Spring提供声明式事务也就是只需要声明。例如Transactional public void createOrder(){ }开发者只关注业务,事务交给Spring管理。五、Spring事务核心思想Spring事务本质依然是AOP。流程调用业务方法 ↓ 事务代理对象 ↓ 开启事务 ↓ 执行目标方法 ↓ 提交事务 ↓ 异常回滚和AOP流程非常类似。因为事务本身就是一种增强逻辑。六、Transactional执行原理我们写Service public class OrderService { Transactional public void createOrder(){ saveOrder(); } }Spring启动时扫描这个类。发现Transactional然后创建代理对象。原对象OrderService变成OrderServiceProxy调用orderService.createOrder();实际上代理对象 ↓ 事务拦截器 ↓ 开启事务 ↓ 真实方法执行 ↓ 提交事务七、Spring事务核心组件Spring事务主要由几个核心类组成。1. PlatformTransactionManager事务管理器接口。负责开启事务提交事务回滚事务接口public interface PlatformTransactionManager { TransactionStatus getTransaction(); void commit(); void rollback(); }不同数据库有不同实现。例如MySQLDataSourceTransactionManagerJPAJpaTransactionManager2. TransactionDefinition事务定义。保存事务配置例如传播行为隔离级别超时时间3. TransactionStatus事务状态。记录当前事务执行情况。八、Spring事务执行流程完整流程Controller调用Service ↓ 进入事务代理 ↓ TransactionInterceptor ↓ 创建事务 ↓ 执行目标方法 ↓ 没有异常 ↓ commit提交 出现异常 ↓ rollback回滚九、事务核心源码入口Spring事务核心TransactionInterceptor它本质是一个MethodInterceptor。也就是AOP拦截器。核心方法invoke()流程invoke(){ 获取事务信息 开启事务 执行业务方法 提交或回滚 }十、事务开启过程调用Transactional public void save(){ }进入TransactionInterceptor然后调用transactionManager.getTransaction()创建事务。例如JDBC事务connection.setAutoCommit(false);关闭自动提交。十一、事务提交业务方法执行成功例如saveOrder();没有异常。执行commit();数据库提交修改。十二、事务回滚如果业务出现异常throw new RuntimeException();Spring捕获异常。执行rollback();数据库恢复原状态。十三、为什么默认RuntimeException才会回滚这是很多开发者容易遇到的问题。例如Transactional public void save(){ throw new Exception(); }发现没有回滚。原因Spring默认规则回滚RuntimeException Error不回滚ExceptionSpring认为检查异常可能是业务可处理异常。如果需要指定Transactional( rollbackFor Exception.class )十四、事务失效常见情况1. 方法不是public例如Transactional private void save(){ }不会生效。原因Spring AOP代理无法增强。2. 同类方法调用例如public void methodA(){ methodB(); } Transactional public void methodB(){ }调用this.methodB();不会经过代理,事务不会生效。3. 对象不是Spring管理例如new UserService();自己创建的对象不会有事务代理。4. 异常被捕获例如try{ save(); }catch(Exception e){ }异常没有抛出,Spring无法感知失败。十五、事务传播行为实际项目中一个事务可能调用另一个事务。例如订单创建调用库存扣减,这就是事务传播。Spring提供Transactional( propagation xxx )常见REQUIRED默认。如果存在事务加入当前事务。不存在创建新事务。REQUIRES_NEW总是创建新事务。挂起当前事务。SUPPORTS有事务加入。没有事务也执行。十六、事务隔离级别数据库并发问题包括脏读读取未提交数据。不可重复读同一数据两次读取结果不同。幻读查询结果数量发生变化。Spring支持Transactional( isolation Isolation.xxx )常见READ_COMMITTED REPEATABLE_READ SERIALIZABLE十七、Spring事务源码核心类重点关注作用核心类事务注解解析TransactionAttributeSource事务拦截TransactionInterceptor事务管理PlatformTransactionManager事务状态TransactionStatus事务同步TransactionSynchronizationManager十八、Spring事务整体流程总结完整流程Transactional ↓ Spring创建代理对象 ↓ 调用代理方法 ↓ TransactionInterceptor拦截 ↓ 开启数据库事务 ↓ 执行目标方法 ↓ 成功 commit ↓ 异常 rollback十九、总结Spring事务的核心不是Transactional注解本身。而是AOP代理 事务管理器 数据库事务。整个过程业务方法 ↓ AOP代理 ↓ 事务拦截器 ↓ 开启事务 ↓ 执行业务 ↓ 提交/回滚理解 Spring 事务之后就能明白为什么Transactional可以自动回滚为什么事务依赖AOP为什么事务有时会失效为什么需要事务传播和隔离级别下一篇文章《Spring框架学习七Spring Boot自动配置原理》将进入 Spring Boot 核心机制分析SpringBootApplication、自动配置以及 Starter 的底层实现。