Skip to content

Spring 声明式事务管理

TIP

Spring 声明式事务管理基于 AOP 实现,开发者只需通过注解声明事务边界,无需编写事务管理代码。

@Transactional 注解

java
@Service
public class OrderService {

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private InventoryDao inventoryDao;

    @Transactional
    public void createOrder(Order order) {
        orderDao.insert(order);
        inventoryDao.decrease(order.getProductId(), order.getQuantity());
        // 事务中任一操作失败都会回滚
    }
}

事务传播行为

java
@Transactional(propagation = Propagation.REQUIRED)  // 默认:支持当前事务,没有则创建
@Transactional(propagation = Propagation.REQUIRES_NEW) // 创建新事务,挂起当前事务
@Transactional(propagation = Propagation.NESTED)      // 嵌套事务
@Transactional(propagation = Propagation.SUPPORTS)    // 支持当前事务,没有则不开启
@Transactional(propagation = Propagation.NOT_SUPPORTED) // 以非事务方式执行
@Transactional(propagation = Propagation.NEVER)       // 必须以非事务方式执行
@Transactional(propagation = Propagation.MANDATORY)   // 必须在事务中执行

事务隔离级别

java
@Transactional(isolation = Isolation.DEFAULT)        // 默认:使用数据库默认级别
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@Transactional(isolation = Isolation.READ_COMMITTED) // 推荐:防止脏读
@Transactional(isolation = Isolation.REPEATABLE_READ) // MySQL 默认
@Transactional(isolation = Isolation.SERIALIZABLE)    // 最高级别,性能最差

回滚规则

java
@Transactional(
    rollbackFor = Exception.class,               // 遇到 Exception 及其子类回滚
    noRollbackFor = IllegalArgumentException.class // 遇到指定异常不回滚
)
public void transfer(Account from, Account to, BigDecimal amount) {
    // ...
}

事务失效的常见场景

java
// 1. 同一个类中方法调用(AOP 代理不生效)
@Service
public class OrderService {

    public void processOrder() {
        this.createOrder(); // 直接调用,事务不生效!
    }

    @Transactional
    public void createOrder() {
        // ...
    }
}

// 解决方法:注入自身代理
@Service
public class OrderService {
    @Autowired
    private OrderService self; // 注入自身代理

    public void processOrder() {
        self.createOrder(); // 通过代理调用,事务生效
    }
}

// 2. 非 public 方法
@Transactional // private 方法不会生效
private void save() { }

// 3. try-catch 吞掉异常
@Transactional
public void save() {
    try {
        // ...
    } catch (Exception e) {
        // 不抛出异常,事务不会回滚
    }
}