Spring事务

一、什么是事务

事务是一组不可分割的数据库操作序列,这些操作要么全部成功执行 ,要么全部不执行,是一个完整的逻辑工作单元。

事务经典例子:银行转账

sql 复制代码
-- 从A账户转100元到B账户
UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A';
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B';

如果没有事务管理,可能出现以下问题:

  1. A账户扣款成功,B账户收款失败 → A的钱消失了
  2. 系统在操作过程中崩溃 → 数据不一致

有了事务机制,就能确保:要么两个操作都成功,要么都失败。

二、事务的四大特性(ACID)

  1. 原子性(Atomicity):事务内的操作要么全部成功,要么全部失败
  2. 一致性(Consistency):事务执行前后数据保持一致状态
  3. 隔离性(Isolation):并发事务之间相互隔离
  4. 持久性(Durability):事务提交后数据永久保存

三、SQL中的事务控制

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

-- 2. 执行一系列操作
INSERT INTO orders (user_id, amount) VALUES (1, 100.00);
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;

-- 3. 根据情况选择
COMMIT;    -- 确认提交,永久保存
-- 或
ROLLBACK;  -- 撤销所有操作

四、Spring事务的使用

1.基础配置

Java 配置方式:

java 复制代码
@Configuration
@EnableTransactionManagement  // 启用事务管理
@ComponentScan("com.example")
public class AppConfig {
    
    @Bean
    public DataSource dataSource() {
        // 配置数据源
        return new DriverManagerDataSource(...);
    }
    
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

Spring Boot 自动配置:

Spring Boot 会自动配置事务管理器,只需要添加依赖:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

2.使用 @Transactional 注解

基本使用

java 复制代码
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Transactional  // 添加事务注解
    public User createUser(User user) {
        // 业务操作
        userRepository.save(user);
        
        // 其他数据库操作
        userRepository.saveLog(user);
        
        // 如果抛出异常,事务会自动回滚
        return user;
    }
}

说明:可以在 application.yml 配置文件中开启事务管理日志,这样就能在控制台看到和事务相关的日志信息了

yml 复制代码
#spring事务管理日志
logging: 
  level: 
    org.springframework.jdbc.support.JdbcTransactionManager: debug

3.@Transactional 参数详解

java 复制代码
@Transactional(
    propagation = Propagation.REQUIRED,      // 传播行为
    isolation = Isolation.DEFAULT,           // 隔离级别
    readOnly = false,                        // 是否只读
    timeout = 30,                            // 超时时间(秒)
    rollbackFor = Exception.class,           // 触发回滚的异常
    noRollbackFor = RuntimeException.class   // 不触发回滚的异常
)
public void businessMethod() {
    // 业务逻辑
}

3.1 事务传播行为(Propagation)

事务的传播行为是指,当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。

java 复制代码
@Service
public class OrderService {
    
    @Transactional(propagation = Propagation.REQUIRED)  // 默认值
    public void placeOrder(Order order) {
        // 如果当前没有事务,就新建一个事务
        // 如果已经存在事务,就加入该事务
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateInventory() {
        // 总是新建一个事务,如果当前有事务则挂起
    }
    
    @Transactional(propagation = Propagation.SUPPORTS)
    public void getOrder() {
        // 如果当前有事务,就加入该事务
        // 如果没有事务,就以非事务方式执行
    }
    
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void sendNotification() {
        // 以非事务方式执行,挂起当前事务
    }
    
    @Transactional(propagation = Propagation.NEVER)
    public void validateData() {
        // 以非事务方式执行,如果当前存在事务则抛出异常
    }
    
    @Transactional(propagation = Propagation.NESTED)
    public void processSubTask() {
        // 如果当前存在事务,则在嵌套事务内执行
        // 嵌套事务可以独立提交或回滚
    }
}

说明:大部分情况下都是使用 REQUIRED 传播行为即可,当我们不希望事务之间互相影响时,可以使用 REQUIRES_NEW 传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都要保证日志记录能够记录成功。

3.2 隔离级别(Isolation)

java 复制代码
@Service
public class AccountService {
    
    @Transactional(isolation = Isolation.READ_COMMITTED)  // 常用
    public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
        // 读取已提交的数据,避免脏读
    }
    
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public BigDecimal getBalance(Long accountId) {
        // 可重复读,MySQL默认级别
    }
    
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void batchUpdate() {
        // 串行化,性能最低但最安全
    }
}
隔离级别 说明
READ UNCOMMITTED 允许读取其他事务未提交的数据
READ COMMITTED 只能读取其他事务已提交的数据
REPEATABLE READ 确保在同一事务中多次读取同一数据,结果一致
SERIALIZABLE 强制事务串行执行,完全隔离

说明:Isolation.DEFAULT 是 Spring 事务中一个特殊的隔离级别常量,表示使用底层数据库的默认隔离级别。

java 复制代码
// Spring 事务隔离级别枚举
public enum Isolation {
    DEFAULT(-1),           // 使用数据库默认级别
    READ_UNCOMMITTED(1),   // 读未提交
    READ_COMMITTED(2),     // 读已提交
    REPEATABLE_READ(4),    // 可重复读
    SERIALIZABLE(8);       // 串行化
    
    private final int value;
    
    Isolation(int value) {
        this.value = value;
    }
}

3.3 触发回滚的异常(rollbackFor)

为什么需要 rollbackFor?

默认情况下,Spring 事务只在运行时异常 (RuntimeException)和错误 (Error)发生时回滚,而受检异常(Checked Exception)不会触发回滚。

java 复制代码
@Service
public class BankService {
    
    @Transactional
    public void transferMoney1() {
        // 运行时异常 → 自动回滚 ✓
        throw new RuntimeException("系统错误");
    }
    
    @Transactional
    public void transferMoney2() throws IOException {
        // 受检异常 → 不会回滚!❌
        throw new IOException("网络异常");
        // 事务会提交!这很危险
    }
}

基本用法

java 复制代码
// 指定单个异常类型
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) throws BusinessException {
    try {
        // 业务逻辑
        validateOrder(order);
        saveOrder(order);
        reduceInventory(order);
        
    } catch (ValidationException e) {
        // 指定 BusinessException 触发回滚
        throw new BusinessException("订单创建失败", e);
    }
}

// 指定多个异常类型
@Transactional(rollbackFor = {
    BusinessException.class,
    PaymentException.class, 
    SQLException.class
})
public void processPayment() {
    // 当这些异常发生时,事务会回滚
}
相关推荐
Elieal2 小时前
基于 Spring MVC + 阿里云通义千问的 AI 助手开发
spring·阿里云·mvc
量子炒饭大师2 小时前
【C++入门】骇客数据面向对象的灵魂锚点——【类与对象】this指针篇
java·c++·dubbo·this·this指针
J_liaty2 小时前
Spring Boot整合Shiro实现权限认证
java·spring boot·后端·shiro
花间相见2 小时前
【JAVA开发】—— Git常用操作
java·开发语言·git
Java程序员威哥2 小时前
云原生Java应用优化实战:资源限制+JVM参数调优,容器启动快50%
java·开发语言·jvm·python·docker·云原生
多多*2 小时前
程序设计工作室1月21日内部训练赛
java·开发语言·网络·jvm·tcp/ip
Engineer邓祥浩2 小时前
设计模式学习(15) 23-13 模版方法模式
java·学习·设计模式
茶本无香2 小时前
设计模式之四:建造者模式(Builder Pattern)详解
java·设计模式·建造者模式
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 高校素拓分管理系统的设计与开发为例,包含答辩的问题和答案
java·eclipse