【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
文章目录事务管理一、事务核心基石ACID四大特性二、事务并发问题与隔离级别2.1 并发事务引发的3大核心读异常2.2 SQL标准4大隔离级别2.3 核心补充MVCC与隔离级别的关联三、Spring事务传播行为3.1 第一类支持当前事务优先加入已有事务3.2 第二类不支持当前事务强制独立/非事务执行3.3 第三类嵌套事务3.4 核心高频传播行为对比四、Transactional底层实现原理4.1 核心前提Spring动态代理机制4.2 完整执行流程事务全生命周期4.3 核心底层组件五、Transactional失效场景全解5.1 第一类代理机制相关失效最常见占比最高5.2 第二类注解属性配置错误导致的失效5.3 第三类异常处理错误导致的失效5.4 第四类特殊场景与底层机制导致的失效六、事务管理最佳实践事务管理本文从基础理论→数据库层实现→Spring框架封装→底层原理→实践坑点全链路系统性梳理事务管理的核心知识体系覆盖ACID特性、隔离级别、传播行为、Transactional底层原理与失效场景五大核心模块。一、事务核心基石ACID四大特性事务是数据库操作的最小不可分割执行单元核心目标是保证一组数据库操作「要么全成功执行要么全失败回滚」最终保障数据一致性。ACID是事务的四大核心特性其中一致性是最终目标原子性、隔离性、持久性是实现一致性的核心保障。特性核心定义数据库层实现手段核心作用原子性Atomicity事务是不可分割的最小单元事务内的所有操作要么全部执行成功要么全部失败回滚不存在「部分执行」的中间状态InnoDBundo log回滚日志逻辑日志记录数据修改前的反向操作事务回滚时通过undo log还原数据到事务开始前的状态保障事务操作的完整性解决「部分成功」导致的数据错乱一致性Consistency事务执行前后数据的完整性约束主键唯一、外键关联、索引约束和业务规则约束如转账前后账户总额不变不被破坏由原子性、隔离性、持久性共同保障同时依赖数据库层的约束校验与业务层的逻辑正确性事务的最终核心目标其他三大特性均为一致性服务隔离性Isolation多个并发执行的事务之间相互隔离、互不干扰避免并发事务互相影响导致的数据异常数据库锁机制MVCC多版本并发控制通过隔离级别定义隔离的严格程度解决并发场景下的事务干扰问题是多线程并发访问数据库的核心保障持久性Durability事务一旦提交成功对数据的修改就是永久的后续的系统宕机、断电、崩溃都不会导致已提交的数据丢失InnoDBredo log重做日志 WAL预写日志机制修改数据前先写redo log事务提交时确保redo log刷盘宕机后可通过redo log恢复数据保障已提交数据的永久生效解决系统崩溃导致的数据丢失问题二、事务并发问题与隔离级别隔离级别是数据库层对事务隔离性的具体落地实现定义了并发事务之间的可见性规则用于解决并发事务引发的读异常问题。2.1 并发事务引发的3大核心读异常异常类型定义核心场景脏读事务A读取了事务B未提交的修改数据若事务B后续回滚事务A读取到的就是无效的脏数据事务B修改数据未提交事务A读取该数据B回滚后A的数据无来源不可重复读同一个事务A内多次读取同一行数据结果不一致核心是中间有其他事务对该行数据执行了update/delete并提交事务A第一次查询数据事务B修改并提交该数据A第二次查询结果与第一次不同幻读同一个事务A内多次执行相同的范围查询返回的行数不一致核心是中间有其他事务执行了insert/delete符合条件的行并提交事务A查询id10的行事务B插入一条id11的行并提交A第二次查询多了一行数据2.2 SQL标准4大隔离级别从低到高分为4个等级隔离级别越高并发性能越差数据安全性越高。隔离级别解决的异常残留的异常核心规则主流数据库适配读未提交Read Uncommitted无脏读、不可重复读、幻读事务可以读取其他事务未提交的修改几乎无生产场景使用读已提交Read Committed, RC脏读不可重复读、幻读事务只能读取其他事务已提交的修改每次查询都生成最新的读视图Oracle、SQL Server默认隔离级别可重复读Repeatable Read, RR脏读、不可重复读理论上的幻读同一个事务内多次读取同一数据的结果完全一致事务启动时生成全局读视图MySQL InnoDB默认隔离级别通过Next-Key Lock临键锁解决了幻读问题串行化Serializable脏读、不可重复读、幻读无并发性能极差事务完全串行执行所有操作全加锁同一时间只允许一个事务执行仅对数据一致性要求极高、无并发要求的场景使用2.3 核心补充MVCC与隔离级别的关联MVCC多版本并发控制是InnoDB实现隔离级别的核心底层机制通过undo log保存数据的历史版本实现「不加锁的读-写并发」RC级别每次执行SELECT语句都会生成一个全新的Read View读视图因此每次都能读到其他事务最新提交的数据无法避免不可重复读。RR级别事务启动后第一次执行SELECT时生成Read View整个事务生命周期内复用该视图因此保证了同一事务内多次读取结果一致实现可重复读。三、Spring事务传播行为传播行为是Spring框架特有的、应用层的事务控制规则与数据库隔离级别完全解耦。它定义了当一个被Transactional注解修饰的方法被另一个事务方法调用时当前事务如何在调用者与被调用者之间传播核心是控制事务的边界、创建、复用与挂起行为。Spring共定义了7种传播行为分为3大类核心默认值为REQUIRED。3.1 第一类支持当前事务优先加入已有事务传播行为核心规则适用场景REQUIRED默认值若当前存在事务就加入该事务若当前无事务就新建一个独立事务。核心特点多个嵌套方法共用同一个事务任意一个方法触发回滚整个事务全量回滚绝大多数常规业务场景是Spring默认的最优解SUPPORTS若当前存在事务就加入该事务若当前无事务就以非事务方式执行以查询为主的方法兼容有事务/无事务场景避免不必要的事务开销MANDATORY强制要求当前必须存在事务若有事务则加入若无事务直接抛出异常核心业务方法必须依赖事务执行防止被无事务场景错误调用3.2 第二类不支持当前事务强制独立/非事务执行传播行为核心规则适用场景REQUIRES_NEW无论当前是否存在事务都新建一个完全独立的事务同时将当前已有事务挂起。核心特点子事务与主事务完全隔离子事务的提交/回滚与主事务互不影响需要独立于主事务提交的操作如操作日志记录、通知推送无论主业务是否成功都需要持久化NOT_SUPPORTED无论当前是否存在事务都以非事务方式执行同时将当前已有事务挂起纯查询操作、不需要事务的轻量方法避免事务带来的性能开销NEVER强制禁止事务无论当前是否存在事务都以非事务方式执行若当前存在事务直接抛出异常绝对不能在事务中执行的操作如跨库非事务性操作、元数据修改3.3 第三类嵌套事务传播行为核心规则适用场景NESTED若当前存在事务就开启一个嵌套子事务基于Savepoint保存点若当前无事务行为与REQUIRED一致。核心特点子事务可独立回滚不影响主事务主事务回滚子事务必须同步回滚精细化回滚场景如主流程下单子流程赠送积分积分发放失败可单独回滚不影响下单主流程3.4 核心高频传播行为对比传播行为事务边界回滚影响范围底层实现REQUIRED多个方法共用同一个事务任意子方法回滚全事务回滚同一个数据库连接REQUIRES_NEW主事务与子事务完全独立两个独立事务子事务回滚不影响主事务主事务回滚不影响已提交的子事务新建数据库连接挂起原连接NESTED主事务下的嵌套子事务从属主事务子事务可独立回滚主事务回滚子事务必回滚同一个连接基于Savepoint保存点四、Transactional底层实现原理Transactional是Spring声明式事务的核心注解本质是基于AOP面向切面编程实现对目标方法进行动态代理在方法执行前后织入事务的开启、提交、回滚逻辑底层完全依赖数据库的事务能力。4.1 核心前提Spring动态代理机制Spring为被Transactional修饰的Bean生成动态代理对象只有通过代理对象调用目标方法才能触发事务拦截逻辑。Spring提供两种代理实现JDK动态代理基于接口实现要求目标类必须实现接口生成接口的代理实现类。CGLIB动态代理基于继承实现目标类无需实现接口生成目标类的子类作为代理类Spring Boot 2.x开始默认使用该方式。关键限制只有public非final、非static的方法才能被动态代理拦截这是后续大量失效场景的核心根源。4.2 完整执行流程事务全生命周期代理对象生成Spring容器启动时扫描所有被Transactional修饰的Bean为其生成动态代理对象注入事务拦截器。方法调用拦截外部调用目标方法时不会直接执行原始业务方法而是先调用代理对象被TransactionInterceptor事务拦截器拦截。事务属性解析事务拦截器通过TransactionAttributeSource解析Transactional注解的配置隔离级别、传播行为、回滚规则、超时时间等。事务管理器创建事务调用核心接口PlatformTransactionManager根据传播行为判断是否新建事务、复用已有事务、挂起现有事务并获取数据库连接。连接线程绑定通过DataSourceUtils将获取到的数据库Connection绑定到当前线程的ThreadLocal中保证同一个事务内的所有操作使用同一个数据库连接这是事务原子性的核心基础。执行业务方法事务开启完成后调用目标Bean的原始业务方法执行数据库操作。异常处理与回滚判断若业务方法抛出异常根据rollbackFor规则判断是否回滚默认仅对RuntimeException和Error触发回滚受检异常Exception默认不回滚。若符合回滚规则调用事务管理器的rollback()方法执行回滚。事务提交若业务方法正常执行完成未抛出符合回滚规则的异常调用事务管理器的commit()方法提交事务。资源清理事务提交/回滚完成后解除ThreadLocal中绑定的数据库连接将连接归还连接池恢复被挂起的事务如有。4.3 核心底层组件组件核心作用PlatformTransactionManagerSpring事务顶层核心接口定义了事务的三大核心操作getTransaction()创建/获取事务、commit()提交、rollback()回滚。常用实现类DataSourceTransactionManagerJDBC/MyBatis本地事务、JtaTransactionManager分布式事务TransactionInterceptor事务核心拦截器实现AOP的MethodInterceptor接口负责在方法执行前后拦截触发事务的全生命周期逻辑TransactionAttributeSource负责解析Transactional注解的配置转换为Spring可识别的TransactionAttribute事务属性对象ThreadLocal线程绑定工具将数据库连接与当前线程绑定保证同一事务内的操作共用同一个连接避免多线程下的连接混乱五、Transactional失效场景全解失效场景的核心本质是违反了Spring动态代理的拦截规则、注解配置不符合预期、异常处理未触发回滚规则、底层数据库不支持事务四大类以下为全场景覆盖含失效原因与解决方案。5.1 第一类代理机制相关失效最常见占比最高方法非public修饰失效原因Spring AOP仅能拦截public方法private、protected、default修饰的方法无法被动态代理拦截注解完全无效。解决方案将事务方法改为public修饰。类内部方法调用this调用失效原因Transactional基于动态代理生效只有外部调用代理对象的方法才会被拦截。类内部通过this调用本类方法调用的是原始对象而非代理对象无法触发事务拦截。典型示例A类的无事务方法methodA()通过this.methodB()调用本类加了Transactional的methodB()methodB的事务完全失效。解决方案最优方案将被调用的事务方法拆分到独立的Bean中通过Spring注入后调用。备选方案在本类中注入自身代理对象通过代理对象调用内部方法。终极方案使用AspectJ静态代理替代Spring动态代理彻底解决内部调用问题。方法被final/static修饰失效原因CGLIB动态代理通过生成目标类的子类实现final方法无法被子类重写static方法属于类而非实例对象均无法被代理拦截注解失效。解决方案移除方法的final、static修饰符改为实例的public非final方法。Bean未被Spring容器管理失效原因Transactional的代理对象由Spring IOC容器生成若目标类未添加Service/Component等注解未被容器管理无法生成代理对象注解失效。解决方案将目标类纳入Spring IOC容器管理。5.2 第二类注解属性配置错误导致的失效rollbackFor配置错误高频生产坑失效原因Transactional默认仅对RuntimeException和Error触发回滚对于受检异常如IOException、SQLException、自定义受检异常默认不会回滚。若未配置rollbackFor抛出受检异常时事务不会回滚。解决方案显式配置Transactional(rollbackFor Exception.class)覆盖所有异常类型避免漏回滚。传播行为配置错误失效原因使用了不支持事务的传播行为如SUPPORTS无事务时以非事务执行、NOT_SUPPORTED强制非事务执行导致事务未被创建。解决方案根据业务场景正确选择传播行为常规场景使用默认的REQUIRED即可。多数据源场景未指定事务管理器失效原因多数据源项目中若未给每个数据源配置独立的事务管理器或未通过transactionManager属性指定对应管理器Transactional无法找到正确的事务管理器导致失效。解决方案多数据源场景下显式指定Transactional(transactionManager xxxTransactionManager)。超时时间配置无效失效原因timeout属性仅对新建的事务生效若传播行为为加入已有事务timeout配置会被忽略部分数据库不支持事务超时设置。解决方案在新建事务的方法上配置timeout确保传播行为为REQUIRED无事务时新建或REQUIRES_NEW。5.3 第三类异常处理错误导致的失效异常被try-catch捕获未向外抛出失效原因Spring事务只有捕获到方法抛出的、符合回滚规则的异常时才会触发回滚。若方法内通过try-catch将异常“吃掉”未向外抛出事务拦截器无法感知异常不会执行回滚。典型示例方法内捕获Exception仅打印日志未重新抛出事务不回滚。解决方案方案1捕获异常后重新抛出符合rollbackFor规则的异常。方案2catch块中手动触发回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();抛出的异常与rollbackFor配置不匹配失效原因配置了rollbackFor 自定义异常类但方法抛出的异常不在配置范围内导致事务不回滚。解决方案rollbackFor配置覆盖所有需要回滚的异常推荐直接配置Exception.class。5.4 第四类特殊场景与底层机制导致的失效多线程调用导致事务失效失效原因Spring事务的数据库连接绑定在ThreadLocal中多线程场景下子线程与主线程不属于同一个ThreadLocal无法获取主线程的数据库连接子线程的操作不在主线程的事务中事务失效。解决方案多线程场景下使用分布式事务如Seata或确保所有事务操作在同一个线程内执行。数据库不支持事务失效原因如MySQL的MyISAM存储引擎不支持事务只有InnoDB支持。若表使用MyISAM引擎Transactional完全无效。解决方案将表的存储引擎改为InnoDB。事务方法内执行DDL语句失效原因create、alter、drop等DDL语句执行后会被数据库隐式提交当前事务导致后续操作报错时无法回滚。解决方案严禁在事务方法内执行DDL语句DDL操作单独处理。嵌套事务NESTED使用错误失效原因NESTED传播行为依赖数据库的Savepoint机制且需要事务管理器开启nestedTransactionAllowed true否则会退化为REQUIRED导致预期的嵌套回滚失效。解决方案使用NESTED时确保事务管理器开启嵌套事务支持且数据库支持Savepoint。六、事务管理最佳实践优先使用声明式事务Transactional避免编程式事务降低代码耦合度。注解必须加在public方法上严禁类内部this调用事务方法必须内部调用时使用代理对象。强制显式配置rollbackFor Exception.class避免受检异常不回滚的生产事故。控制事务粒度尽可能小避免大事务严禁在事务内执行RPC调用、HTTP请求、文件IO等耗时操作减少锁持有时间提升并发性能。常规场景使用默认的REQUIRED传播行为需要独立事务用REQUIRES_NEW精细化回滚用NESTED避免滥用传播行为。多数据源场景下必须显式指定transactionManager避免事务失效。严禁在事务内执行DDL语句防止隐式提交导致的回滚失效。线上环境避免使用串行化、读未提交隔离级别MySQL默认RR级别、Oracle默认RC级别为最优解。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2448762.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!