spring事务相关信息量的沉淀

1.什么是事务

2.如何使用事务

3.在使用事务的时候会出现哪些特殊的场景

4.事务失效的常见场景

5.事务实现的原理是什么

1. 什么是事务

事务(Transaction)是数据库管理系统 执行过程中的一个逻辑单元,它由一组操作(通常是一组SQL语句)组成,这些操作要么全部成功 ,要么全部失败(即全部不执行)。

事务是为了保证数据的一致性和完整性而提出的概念。最经典的例子就是银行转账:从A账户扣款和向B账户加款这两个操作必须作为一个整体,要么都成功,要么都失败,不能出现一边扣了另一边没加的情况。

事务的四大特性(ACID):

  • 原子性(Atomicity):事务中的所有操作要么全部提交成功,要么全部失败回滚。
  • 一致性(Consistency):事务执行前后,数据从一个一致状态变到另一个一致状态(比如转账前后总金额不变)。
  • 隔离性(Isolation):并发执行的事务之间互相不干扰,一个事务的中间状态对其他事务不可见。
  • 持久性(Durability):事务一旦提交,对数据的改变就是永久性的,即使系统崩溃也不会丢失。

2. 如何使用事务

在不同的技术栈中使用方式不同,这里以最常用的 MySQL + Spring(Java)为例。

2.1 在MySQL中直接使用

sql 复制代码
-- 开始事务
START TRANSACTION;  或  BEGIN;

-- 执行一组SQL
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;

-- 如果都成功,提交
COMMIT;

-- 如果出错,回滚
ROLLBACK;

2.2 在Spring Boot中使用(声明式事务,最常用)

java 复制代码
@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;

    // 在方法上添加@Transactional注解即可
    @Transactional
    public void transfer(Long fromId, Long toId, int amount) {
        userMapper.decreaseBalance(fromId, amount);
        // 如果这里抛出异常,上面扣款操作会自动回滚
        userMapper.increaseBalance(toId, amount);
    }
}

2.3 编程式事务(更灵活,但代码侵入性强)

java 复制代码
@Autowired
private TransactionTemplate transactionTemplate;

public void doSomething() {
    transactionTemplate.execute(status -> {
        // 业务代码
        return result;
    });
}

关键点 :实际开发中99%的场景使用 @Transactional 即可,需要开启事务管理器配置(Spring Boot自动配置)。


3. 使用事务时会出现哪些特殊场景

特殊场景 说明 示例/解决方案
事务传播行为 一个事务方法调用另一个事务方法,事务如何传递? REQUIRED(默认,加入现有事务)、REQUIRES_NEW(挂起当前,新建事务)等7种
嵌套事务 内层事务回滚是否影响外层? MySQL的Savepoint机制,Spring的NESTED传播级别
多数据源事务 一个方法操作两个不同数据库 需使用分布式事务(如Seata、2PC、TCC)
只读事务 标记事务只读,数据库可以优化 @Transactional(readOnly = true),适用于查询
超时回滚 事务执行超过设定时间自动回滚 @Transactional(timeout = 30),防止长事务锁表
回滚规则 默认只有RuntimeException回滚,检查异常不回滚 可通过rollbackFor指定:@Transactional(rollbackFor = Exception.class)

4. 事务失效的常见场景(高频面试题)

这是实际开发中非常容易踩坑的地方,即使写了 @Transactional 也不一定生效:

失效场景 原因 解决方案
方法内部调用 同一个类内A方法(无事务)调用B方法(有事务),事务不生效 通过代理对象调用(自己注入自己,或AopContext.currentProxy()
异常被catch吞掉 方法内try-catch了异常,没有往外抛 要么手动回滚:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(),要么抛出异常
抛出检查异常(非RuntimeException) 默认只对RuntimeException回滚 配置rollbackFor = Exception.class
事务方法不是public Spring动态代理要求方法为public 改为public
数据库引擎不支持事务 MySQL的MyISAM引擎不支持事务 使用InnoDB引擎
事务传播行为配置错误 比如配置为Propagation.NOT_SUPPORTED 检查传播级别
Spring未启用事务管理 缺少@EnableTransactionManagement或事务管理器Bean 检查配置(Spring Boot自动配置通常OK)

最经典的失效代码:

java 复制代码
@Service
public class OrderService {
    
    public void createOrder() {
        // 内部调用,事务失效!!!
        this.updateStock(); 
    }
    
    @Transactional
    public void updateStock() {
        // 这个事务不会生效
    }
}

5. 事务实现的原理是什么

事务的实现原理可以分为数据库层面框架层面两个维度。

5.1 数据库层面(以MySQL InnoDB为例)
  • 原子性 :通过 Undo Log 实现。修改数据前,先将旧值写入Undo Log,回滚时用旧值覆盖。
  • 持久性 :通过 Redo Log 实现。事务提交时,先写Redo Log(顺序写,性能高),再异步刷盘。即使数据库崩溃,重启后根据Redo Log恢复已提交的事务。
  • 隔离性 :通过 锁 + MVCC(多版本并发控制) 实现。每行数据有多个版本(通过隐藏列DB_TRX_ID、DB_ROLL_PTR等),读操作读快照,写操作加锁。
  • 一致性:是原子性、隔离性、持久性共同保证的结果。
5.2 Spring框架层面(声明式事务原理)

核心:AOP(动态代理)

  1. Spring 启动时,扫描所有带有 @Transactional 的Bean。
  2. 为这些Bean创建代理对象(JDK动态代理或CGLIB)。
  3. 代理对象在执行目标方法前后,插入事务控制逻辑:
java 复制代码
// 伪代码示意
public Object invoke(MethodInvocation invocation) {
    if (方法没有@Transactional) {
        return invocation.proceed();
    }
    // 1. 开启事务
    TransactionStatus status = transactionManager.getTransaction();
    try {
        // 2. 执行目标方法(业务代码)
        Object result = invocation.proceed();
        // 3. 提交事务
        transactionManager.commit(status);
        return result;
    } catch (Exception e) {
        // 4. 满足回滚条件则回滚
        transactionManager.rollback(status);
        throw e;
    }
}

关键组件

  • TransactionManager:事务管理器(如DataSourceTransactionManager)
  • TransactionDefinition:事务属性(隔离级别、传播行为等)
  • TransactionStatus:当前事务状态

总结

问题 核心答案
事务是什么 一组要么全成功要么全失败的操作,拥有ACID特性
如何使用 SQL用BEGIN/COMMIT,Java用@Transactional
特殊场景 传播行为、嵌套事务、多数据源、只读事务、超时等
失效原因 内部调用、异常被吞、非public、引擎不支持等
实现原理 数据库用Undo/Redo Log+MVCC;Spring用AOP动态代理
相关推荐
shinelord明2 小时前
【云计算】k8sclient API 镜像操作 Java 类封装
java·kubernetes·云计算
basketball6162 小时前
C++ 多态完全指南:同一个接口,千变万化的行为
java·开发语言·c++
KANGBboy2 小时前
java知识二(程序流程控制)
java·开发语言
Dicky-_-zhang2 小时前
JWT令牌安全实践详解
java·jvm
qq7422349842 小时前
全面深入的C#核心知识体系与编程实践精要——从语法基础到高级特性系统学习指南
java·算法·c#
萌新小码农‍2 小时前
Python的input函数
java·前端·python
NiceCloud喜云2 小时前
AutoClaw 接入自定义 Anthropic 端点:让 Kanban 工作流跑在自己的模型路由上
java·开发语言·c++·人工智能·python·eclipse·batch
马尔斯的蓝色3 小时前
[特殊字符] Java 集成 Elasticsearch 实战指南
java
aloha_7893 小时前
信息系统项目管理师选择题考前真题错题笔记汇总
java·笔记·学习·tomcat