1. 事务核心概念
1.1 什么是事务
事务是数据库操作的基本单位,它满足 ACID 四大特性:
- Atomic(原子性):一个事务中的所有操作要么全部成功,要么全部失败回滚
- Consistency(一致性):事务执行前后,数据库状态保持一致
- Isolation(隔离性):并发事务之间相互隔离,不互相干扰
- Durability(持久性):事务提交后,其结果永久保存在数据库中
sql
BEGIN;
UPDATE account SET balance = balance - 100 WHERE user_id = 1;
UPDATE account SET balance = balance + 100 WHERE user_id = 2;
COMMIT;
1.2 Spring 事务两种开发方式
声明式事务 :使用 @Transactional 注解,配置式管理
java
@Transactional(rollbackFor = Exception.class)
public void transferMoney(String from, String to, BigDecimal amount) {
// 转账逻辑
}
编程式事务:手动编写事务代码,精细控制
java
@Service
public class OrderService {
@Autowired
private TransactionTemplate transactionTemplate;
public void createOrder(Order order) {
transactionTemplate.execute(status -> {
orderMapper.insert(order);
orderItemMapper.batchInsert(order.getItems());
return true;
});
}
}
2. 事务传播行为
事务传播行为定义了事务方法的调用关系,当一个事务方法调用另一个事务方法时,如何决定事务的创建和参与方式。
Spring 定义了 7 种传播行为:
| 传播行为 | 说明 |
|---|---|
REQUIRED(默认) |
如果当前有事务,加入该事务;如果没有,创建新事务 |
REQUIRES_NEW |
总是创建新事务,挂起当前事务 |
SUPPORTS |
如果当前有事务,加入事务;如果没有,以非事务执行 |
NOT_SUPPORTED |
以非事务执行,挂起当前事务 |
MANDATORY |
必须在一个事务中运行,否则抛出异常 |
NEVER |
必须不在事务中运行,否则抛出异常 |
NESTED |
如果当前有事务,在嵌套事务中执行;如果没有,创建新事务 |
2.1 REQUIRED vs REQUIRES_NEW 实战区别
java
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private AccountService accountService;
@Transactional
public void createOrder(Order order) {
// 订单创建在当前事务中
orderMapper.insert(order);
// 扣款独立事务,即使失败也不影响订单创建
accountService.deductMoney(order.getUserId(), order.getAmount());
// 如果扣款失败抛出异常,订单已经创建成功了
// 需要根据业务决定是否回滚
}
}
@Service
public class AccountService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void deductMoney(Long userId, BigDecimal amount) {
// 这个方法有独立事务
// 无论外层事务成功与否,这个事务都会提交
}
}
2.2 NESTED 嵌套事务
NESTED 利用 Savepoint 机制实现嵌套事务:
java
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private InventoryService inventoryService;
@Transactional
public void createOrder(Order order) {
// 插入订单 - 主事务
orderMapper.insert(order);
try {
// 扣减库存 - 嵌套事务
// 如果失败,只会回滚到这个保存点
inventoryService.deduct(order.getItems());
} catch (Exception e) {
// 订单仍然存在,可以做补偿处理
log.error("库存扣减失败", e);
}
}
}
3. 事务隔离级别
隔离级别定义了并发事务之间的可见性问题。
3.1 四种隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
READ_UNCOMMITTED |
✓ | ✓ | ✓ |
READ_COMMITTED |
✗ | ✓ | ✓ |
REPEATABLE_READ |
✗ | ✗ | ✓ |
SERIALIZABLE |
✗ | ✗ | ✗ |
- 脏读:读取到其他事务未提交的数据
- 不可重复读:同一查询在不同时间返回不同结果
- 幻读:同一查询在不同时间返回不同数量的行
3.2 Spring 中的配置
java
@Transactional(isolation = Isolation.READ_COMMITTED)
public void transferMoney(String from, String to, BigDecimal amount) {
// 业务逻辑
}
3.3 MySQL 默认隔离级别
MySQL InnoDB 默认使用 REPEATABLE_READ,通过 MVCC 机制实现非阻塞读。
sql
-- 查看当前会话隔离级别
SELECT @@transaction_isolation;
-- 查看全局隔离级别
SELECT @@global.transaction_isolation;
-- 设置隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
4. @Transactional 原理
4.1 核心原理:动态代理
@Transactional 的本质是 AOP 动态代理。当 Spring 扫描到 @Transactional 注解时,会为目标类创建代理对象,在方法执行前后添加事务管理逻辑。
JDK/CGLIB 代理对象
方法返回
返回结果
目标对象
真实业务逻辑
客户端
调用 createOrder()
事务切面
调用目标方法
提交/回滚事务
4.2 代理创建流程
java
// Spring 事务自动配置入口
@Configuration
@EnableTransactionManagement // 启用事务管理
public class TransactionAutoConfiguration {
@Bean
public TransactionInterceptor transactionInterceptor() {
// 创建事务拦截器
return new TransactionInterceptor();
}
@Bean
public BeanFactoryTransactionAttributeSourceAdvisor
transactionAdvisor() {
// 将拦截器封装为 Advisor
return new BeanFactoryTransactionAttributeSourceAdvisor();
}
}
4.3 TransactionInterceptor 执行流程
java
public class TransactionInterceptor extends MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 1. 获取事务属性
TransactionAttributeSource tas = getTransactionAttributeSource();
TransactionAttribute ta = tas.getTransactionAttribute(
invocation.getMethod(), invocation.getThis());
// 2. 获取事务管理器
PlatformTransactionManager tm = determineTransactionManager(ta);
// 3. 执行事务
return invokeWithinTransaction(
invocation.getMethod(),
invocation.getThis(),
ta,
invocation::proceed
);
}
protected Object invokeWithinTransaction(
Method method,
Object target,
TransactionAttribute ta,
InvocationCallback invocation) throws Throwable {
// 获取事务
TransactionInfo txInfo = createTransactionIfNecessary(ta, method);
try {
// 执行目标方法
Object result = invocation.proceedWithInvocation();
// 提交事务
commitTransactionAfterReturning(txInfo);
return result;
} catch (Throwable ex) {
// 回滚事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
} finally {
// 清理事务信息
cleanupTransactionInfo(txInfo);
}
}
}
4.4 事务管理器获取
java
protected PlatformTransactionManager determineTransactionManager(
TransactionAttribute txAttr) {
// 1. 按 beanName 查找
if (txAttr != null && txAttr.getQualifier() != null) {
return lookupTransactionManager(txAttr.getQualifier());
}
// 2. 按 bean 类型查找
if (getTransactionManagerBeanNames().length > 0) {
Object tm = getTransactionManagerBeanNames().length == 1
? getDefaultTransactionManager()
: getTransactionManagerBeanNames();
return lookupTransactionManager(tm);
}
// 3. 返回默认事务管理器
return getDefaultTransactionManager();
}
5. @Transactional 失效场景
5.1 同一个类中方法调用
java
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
// 开启事务
orderMapper.insert(order);
// this 调用不会触发代理,事务无效
this.processPayment(order);
}
@Transactional
public void processPayment(Order order) {
// 不会开启新事务
// 使用当前事务(如果有)
paymentMapper.update(order);
}
}
解决方案:注入自身或使用 AopContext
java
@Service
public class OrderService {
@Autowired
private OrderService self; // 注入自身
@Transactional
public void createOrder(Order order) {
orderMapper.insert(order);
// 通过代理对象调用,事务生效
self.processPayment(order);
}
}
5.2 非 public 方法
java
@Service
public class OrderService {
// 事务无效 - protected/private 方法
@Transactional
void createOrderInternal(Order order) {
orderMapper.insert(order);
}
}
Spring 事务基于 AOP,代理方法必须是 public。
5.3 异常被捕获
java
@Transactional
public void createOrder(Order order) {
try {
orderMapper.insert(order);
} catch (Exception e) {
// 异常被捕获,事务不会回滚
log.error("创建订单失败", e);
}
}
解决方案:配置异常回滚
java
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
try {
orderMapper.insert(order);
} catch (Exception e) {
// 手动回滚
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
throw new BusinessException("创建订单失败", e);
}
}
5.4 传播行为配置错误
java
// 当前方法在 NOT_SUPPORTED 事务中
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void createOrder(Order order) {
// 不会开启事务
orderMapper.insert(order);
}
5.5 数据库不支持事务
java
// MyISAM 存储引擎不支持事务
@Transactional
public void createOrder(Order order) {
// 事务不会生效
orderMapper.insert(order);
}
5.6 多数据源事务
多数据源情况下,Spring 默认只支持单数据源事务。多数据源事务需要使用 JTA 或 Seata。
java
// 使用 Seata 分布式事务
@GlobalTransactional
public void createOrder(Order order) {
// 订单库
orderMapper.insert(order);
// 库存库(远程)
remoteInventoryService.deduct(order.getItems());
// 支付库(远程)
remotePaymentService.pay(order.getPayment());
}
6. TransactionTemplate 编程式事务
6.1 基本用法
java
@Service
public class OrderService {
@Autowired
private TransactionTemplate transactionTemplate;
public void createOrder(Order order) {
transactionTemplate.execute(status -> {
orderMapper.insert(order);
orderItemMapper.batchInsert(order.getItems());
// 手动标记回滚
// status.setRollbackOnly();
return true;
});
}
}
6.2 带返回值和超时
java
public BigDecimal calculateOrderTotal(Long orderId) {
return transactionTemplate.execute(status -> {
status.setTimeout(30); // 30秒超时
Order order = orderMapper.selectById(orderId);
List<OrderItem> items = orderItemMapper.selectByOrderId(orderId);
return items.stream()
.map(OrderItem::getPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add);
});
}
6.3 声明式 vs 编程式
| 特性 | 声明式事务 | 编程式事务 |
|---|---|---|
| 代码侵入 | 低 | 高 |
| 精细控制 | 差 | 好 |
| 学习成本 | 低 | 高 |
| 适用场景 | 简单业务 | 复杂事务逻辑 |
7. Spring 事务底层实现
7.1 TransactionSynchronizationManager
Spring 通过 TransactionSynchronizationManager 管理线程本地的事务状态:
java
public abstract class TransactionSynchronizationManager {
// 事务资源(Connection、Session 等)
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 当前事务信息
private static final ThreadLocal<TransactionInfo> currentTransactionInfo =
new NamedThreadLocal<>("Current transaction info");
// 事务同步回调
private static final ThreadLocal<Set<TransactionSynchronization>>
synchronizations = new NamedThreadLocal<>("Transaction synchronizations");
}
7.2 事务执行流程
数据库 TransactionManager 代理对象 客户端 数据库 TransactionManager 代理对象 客户端 createOrder() getTransaction() 获取数据库连接 开启事务(关闭自动提交) 返回 TransactionStatus 执行目标方法 执行 SQL commit() 提交事务 提交成功 返回 返回结果
7.3 事务同步回调
java
@Transactional
public void createOrder(Order order) {
// 注册事务完成后执行的回调
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void afterCommit() {
// 事务提交后发送消息通知
messageQueue.send(order);
}
@Override
public void afterCompletion(int status) {
// 事务完成后(无论成功或失败)
log.info("事务完成, status: {}", status);
}
}
);
orderMapper.insert(order);
}
8. 最佳实践
8.1 事务范围最小化
java
// 不推荐:事务范围过大
@Transactional
public void createOrder(Order order) {
// 1. 校验参数(不需要事务)
validateOrder(order);
// 2. 创建订单(需要事务)
orderMapper.insert(order);
// 3. 发送消息(不需要事务,可能导致长事务)
messageQueue.send(order);
}
// 推荐:拆分事务边界
public void createOrder(Order order) {
validateOrder(order);
// 只在必要的地方加事务
transactionTemplate.execute(status -> {
orderMapper.insert(order);
return null;
});
// 事务外执行
messageQueue.send(order);
}
8.2 异常处理规范
java
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
try {
orderMapper.insert(order);
} catch (DuplicateKeyException e) {
// 业务异常,手动回滚
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
throw new BusinessException("订单号重复");
}
}
8.3 只读事务优化
java
@Transactional(readOnly = true)
public List<Order> listOrders() {
// 告诉数据库优化查询
// 可能开启读写分离的从库
return orderMapper.selectList(null);
}
9. 总结
Spring 事务是 Spring Framework 的核心功能之一,理解其原理对开发高质量应用至关重要。
- 传播行为 决定了事务方法之间的协作方式,
REQUIRED是最常用的 - @Transactional 基于动态代理实现,同一个类中调用会失效
- TransactionTemplate 提供更精细的事务控制,适合复杂业务场景
- 失效场景需要特别注意:同类调用、非 public 方法、异常捕获、传播行为配置等
掌握这些知识点,能够帮助你更好地应对面试和实际开发中的事务问题。