Spring 事务全面详解
一、事务基础概念
1.1 什么是事务?
事务是一组要么全部成功、要么全部失败的数据库操作单元。它有四大特性(ACID):
java
// ACID 特性示例
public class TransactionACID {
// 1. Atomicity(原子性):事务不可分割
@Transactional
public void transferMoney(Account from, Account to, BigDecimal amount) {
// 要么两个操作都成功,要么都失败
from.withdraw(amount); // 扣款
to.deposit(amount); // 存款
}
// 2. Consistency(一致性):数据始终保持有效状态
// 转账前后,总金额保持不变
// 3. Isolation(隔离性):事务间互不干扰
// 多个转账操作同时进行,互相不影响
// 4. Durability(持久性):事务提交后永久保存
// 转账成功后,数据永久存储
}
1.2 Spring 事务的作用
Spring 事务管理提供了:
- 声明式事务:通过注解配置
- 编程式事务:通过代码控制
- 统一抽象:支持多种数据访问技术(JDBC、JPA、Hibernate等)
二、Spring 事务的核心接口
2.1 关键接口关系
classDiagram
class PlatformTransactionManager {
<>
+getTransaction(TransactionDefinition): TransactionStatus
+commit(TransactionStatus): void
+rollback(TransactionStatus): void
}
class TransactionDefinition {
<>
+PROPAGATION_REQUIRED
+PROPAGATION_REQUIRES_NEW
+getIsolationLevel()
+getTimeout()
+isReadOnly()
}
class TransactionStatus {
<>
+isNewTransaction()
+hasSavepoint()
+setRollbackOnly()
+isRollbackOnly()
}
PlatformTransactionManager <|-- DataSourceTransactionManager
PlatformTransactionManager <|-- JpaTransactionManager
PlatformTransactionManager <|-- HibernateTransactionManager
DataSourceTransactionManager : +JDBC事务
JpaTransactionManager : +JPA事务
HibernateTransactionManager : +Hibernate事务
2.2 主要实现类
java
// 1. JDBC 事务管理器
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// 2. JPA 事务管理器
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
return new JpaTransactionManager(emf);
}
// 3. Hibernate 事务管理器
@Bean
public PlatformTransactionManager transactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
三、事务的传播行为(Propagation)
3.1 七种传播行为详解
java
@Service
public class PropagationService {
// 1. REQUIRED(默认):如果当前有事务,则加入;否则新建事务
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 有事务则加入,没有则新建
}
// 2. REQUIRES_NEW:总是新建事务,挂起当前事务(如果有)
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 总是新建独立事务
// 外层事务回滚不影响这里,这里回滚也不影响外层
}
// 3. SUPPORTS:如果当前有事务,则加入;否则非事务运行
@Transactional(propagation = Propagation.SUPPORTS)
public void methodC() {
// 查询方法常用,有事务用事务,没事务直接查
}
// 4. NOT_SUPPORTED:非事务运行,挂起当前事务(如果有)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodD() {
// 强制非事务执行
// 适用于不需要事务的批量操作
}
// 5. MANDATORY:必须存在事务,否则抛异常
@Transactional(propagation = Propagation.MANDATORY)
public void methodE() {
// 必须在事务中调用,否则 IllegalTransactionStateException
}
// 6. NEVER:必须非事务运行,否则抛异常
@Transactional(propagation = Propagation.NEVER)
public void methodF() {
// 必须在非事务中调用
}
// 7. NESTED:嵌套事务,保存点机制
@Transactional(propagation = Propagation.NESTED)
public void methodG() {
// 嵌套子事务
// 外层回滚,内层一定回滚
// 内层回滚,外层可以选择捕获异常继续
}
}
3.2 传播行为嵌套示例
java
@Service
@Slf4j
public class NestedTransactionService {
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
log.info("外层事务开始");
userRepository.save(new User("张三"));
try {
innerMethodRequiresNew(); // 独立事务
} catch (Exception e) {
log.error("内层异常被捕获", e);
}
try {
innerMethodNested(); // 嵌套事务
} catch (Exception e) {
log.error("嵌套异常被捕获", e);
}
userRepository.save(new User("李四"));
log.info("外层事务结束");
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethodRequiresNew() {
log.info("REQUIRES_NEW 事务开始");
userRepository.save(new User("王五"));
throw new RuntimeException("REQUIRES_NEW 失败");
// 异常不会影响外层事务
}
@Transactional(propagation = Propagation.NESTED)
public void innerMethodNested() {
log.info("NESTED 事务开始");
userRepository.save(new User("赵六"));
throw new RuntimeException("NESTED 失败");
// 外层可以回滚到保存点
}
}
四、事务的隔离级别(Isolation)
4.1 四种隔离级别
java
@Service
public class IsolationService {
// 1. READ_UNCOMMITTED(读未提交)- 最低级别
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void readUncommitted() {
// 可能读到其他事务未提交的数据(脏读)
}
// 2. READ_COMMITTED(读已提交)- 默认级别
@Transactional(isolation = Isolation.READ_COMMITTED)
public void readCommitted() {
// 只能读到已提交的数据
// 但可能出现不可重复读问题
}
// 3. REPEATABLE_READ(可重复读)- MySQL 默认
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void repeatableRead() {
// 同一事务中多次读取结果一致
// 但可能出现幻读问题
}
// 4. SERIALIZABLE(串行化)- 最高级别
@Transactional(isolation = Isolation.SERIALIZABLE)
public void serializable() {
// 完全串行执行,性能最差
}
}
4.2 隔离问题演示
java
@Service
@Slf4j
public class IsolationProblemDemo {
// 脏读问题:读到未提交的数据
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void dirtyReadProblem() {
// 事务A修改数据但未提交
// 事务B能读到A未提交的数据
// 如果A回滚,B读到的就是脏数据
}
// 不可重复读问题:同一事务中两次读取结果不同
@Transactional(isolation = Isolation.READ_COMMITTED)
public void nonRepeatableReadProblem() {
User user1 = userRepository.findById(1L); // 第一次读取
// 另一个事务修改并提交了数据
User user2 = userRepository.findById(1L); // 第二次读取
// user1 和 user2 可能不同!
}
// 幻读问题:同一查询条件返回不同行数
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void phantomReadProblem() {
List<User> list1 = userRepository.findByName("张三"); // 返回2条
// 另一个事务插入了一条 name="张三" 的记录并提交
List<User> list2 = userRepository.findByName("张三"); // 返回3条!
// 行数变了!
}
}
五、Spring 事务的实现原理
5.1 AOP 代理机制
java
// Spring 创建代理对象的伪代码
public class TransactionProxyCreator {
public Object createProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new TransactionInterceptor(target) // 事务拦截器
);
}
}
// 事务拦截器
class TransactionInterceptor implements InvocationHandler {
private Object target;
private PlatformTransactionManager transactionManager;
public Object invoke(Object proxy, Method method, Object[] args) {
// 1. 检查方法是否有 @Transactional
if (!hasTransactionalAnnotation(method)) {
return method.invoke(target, args); // 直接执行
}
// 2. 开启事务
TransactionStatus status = transactionManager.getTransaction(
getTransactionDefinition(method)
);
try {
// 3. 执行业务方法
Object result = method.invoke(target, args);
// 4. 提交事务
transactionManager.commit(status);
return result;
} catch (Exception e) {
// 5. 回滚事务
transactionManager.rollback(status);
throw e;
}
}
}
5.2 自调用问题详解
java
@Service
public class SelfInvocationService {
// 情况1:自调用,事务不生效
@Transactional
public void methodA() {
System.out.println("methodA 事务: " +
TransactionSynchronizationManager.getCurrentTransactionName());
this.methodB(); // ❌ 直接调用,绕过代理
// 输出:methodB 事务: null(没有事务!)
}
@Transactional
public void methodB() {
System.out.println("methodB 事务: " +
TransactionSynchronizationManager.getCurrentTransactionName());
}
// 情况2:通过代理调用,事务生效
@Autowired
@Lazy
private SelfInvocationService selfProxy;
@Transactional
public void methodC() {
System.out.println("methodC 事务: " +
TransactionSynchronizationManager.getCurrentTransactionName());
selfProxy.methodD(); // ✅ 通过代理调用
// 输出:methodD 事务: xxx(有事务!)
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodD() {
System.out.println("methodD 事务: " +
TransactionSynchronizationManager.getCurrentTransactionName());
}
}
5.3 事务同步管理器
java
// TransactionSynchronizationManager 关键方法
public abstract class TransactionSynchronizationManager {
// 当前线程的事务状态
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 当前事务名称
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
// 是否只读
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
// 隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
// 是否实际有事务
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
}
六、声明式事务配置
6.1 注解配置
java
// 完整的 @Transactional 注解使用
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
// 事务管理器 Bean 名称
String value() default "";
String transactionManager() default "";
// 传播行为
Propagation propagation() default Propagation.REQUIRED;
// 隔离级别
Isolation isolation() default Isolation.DEFAULT;
// 超时时间(秒)
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
// 是否只读
boolean readOnly() default false;
// 哪些异常回滚
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
// 哪些异常不回滚
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
6.2 XML 配置
xml
<!-- XML 配置方式 -->
<beans>
<!-- 1. 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 2. 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 查询方法:只读 -->
<tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="query*" read-only="true" propagation="SUPPORTS"/>
<!-- 增删改方法:需要事务 -->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<!-- 其他方法:默认配置 -->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 3. 配置 AOP -->
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* com.example.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
</aop:config>
</beans>
6.3 Java 配置
java
@Configuration
@EnableTransactionManagement // 启用事务管理
public class TransactionConfig {
// 配置事务管理器
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// 配置事务通知(编程式)
@Bean
public TransactionInterceptor transactionInterceptor(
PlatformTransactionManager transactionManager) {
NameMatchTransactionAttributeSource source =
new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
readOnlyTx.setReadOnly(true);
readOnlyTx.setPropagationBehavior(Propagation.SUPPORTS.value());
RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
requiredTx.setRollbackRules(
Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
requiredTx.setPropagationBehavior(Propagation.REQUIRED.value());
requiredTx.setTimeout(5); // 5秒超时
// 方法名匹配规则
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("get*", readOnlyTx);
txMap.put("find*", readOnlyTx);
txMap.put("save*", requiredTx);
txMap.put("update*", requiredTx);
txMap.put("delete*", requiredTx);
source.setNameMap(txMap);
return new TransactionInterceptor(transactionManager, source);
}
// 配置 AOP
@Bean
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor =
new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionInterceptor(transactionInterceptor);
return advisor;
}
}
七、编程式事务
7.1 TransactionTemplate
java
@Service
public class ProgrammaticTransactionService {
private final TransactionTemplate transactionTemplate;
private final UserRepository userRepository;
public ProgrammaticTransactionService(
PlatformTransactionManager transactionManager,
UserRepository userRepository) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
this.userRepository = userRepository;
// 配置 TransactionTemplate
transactionTemplate.setPropagationBehavior(Propagation.REQUIRED.value());
transactionTemplate.setIsolationLevel(Isolation.READ_COMMITTED.value());
transactionTemplate.setTimeout(30); // 30秒
transactionTemplate.setReadOnly(false);
}
// 使用 TransactionTemplate
public void createUsers(List<User> users) {
// 方式1:使用 TransactionCallback
List<String> ids = transactionTemplate.execute(status -> {
List<String> result = new ArrayList<>();
for (User user : users) {
userRepository.save(user);
result.add(user.getId());
// 可以设置保存点
if (users.indexOf(user) == 5) {
Object savepoint = status.createSavepoint();
try {
// 可能失败的操作
riskyOperation();
} catch (Exception e) {
status.rollbackToSavepoint(savepoint); // 回滚到保存点
}
}
}
return result;
});
// 方式2:使用 TransactionCallbackWithoutResult
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
for (User user : users) {
userRepository.save(user);
// 可以手动回滚
if (user.getName().equals("invalid")) {
status.setRollbackOnly(); // 标记为只回滚
}
}
}
});
}
}
7.2 PlatformTransactionManager 直接使用
java
@Service
public class PlatformTransactionManagerService {
private final PlatformTransactionManager transactionManager;
private final UserRepository userRepository;
public void complexTransaction() {
// 1. 定义事务属性
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setPropagationBehavior(Propagation.REQUIRED.value());
definition.setIsolationLevel(Isolation.READ_COMMITTED.value());
definition.setTimeout(30);
definition.setReadOnly(false);
definition.setName("complexTransaction");
// 2. 开启事务
TransactionStatus status = transactionManager.getTransaction(definition);
try {
// 3. 执行业务逻辑
userRepository.save(new User("张三"));
// 嵌套事务
DefaultTransactionDefinition nestedDef = new DefaultTransactionDefinition();
nestedDef.setPropagationBehavior(Propagation.NESTED.value());
TransactionStatus nestedStatus = transactionManager.getTransaction(nestedDef);
try {
userRepository.save(new User("李四"));
transactionManager.commit(nestedStatus); // 提交嵌套事务
} catch (Exception e) {
transactionManager.rollback(nestedStatus); // 回滚嵌套事务
throw e;
}
// 4. 提交主事务
transactionManager.commit(status);
} catch (Exception e) {
// 5. 回滚主事务
transactionManager.rollback(status);
throw e;
}
}
}
八、常见问题与解决方案
8.1 事务失效的 8 种情况
java
@Service
public class TransactionFailureDemo {
// 1. 非 public 方法 ❌
@Transactional
private void privateMethod() {
// 事务不生效
}
// 2. 自调用 ❌
@Transactional
public void methodA() {
this.methodB(); // 事务不生效
}
@Transactional
public void methodB() { }
// 3. 异常被捕获 ❌
@Transactional
public void methodC() {
try {
userRepository.save(user);
throw new RuntimeException();
} catch (Exception e) {
// 异常被捕获,事务不会回滚
}
}
// 4. 异常类型不匹配 ❌
@Transactional(rollbackFor = RuntimeException.class)
public void methodD() throws Exception {
throw new Exception(); // 不是 RuntimeException,不会回滚
}
// 5. 多线程调用 ❌
@Transactional
public void methodE() {
new Thread(() -> {
userRepository.save(user); // 新线程,事务不生效
}).start();
}
// 6. 不支持事务的数据库 ❌
// 如 MySQL 的 MyISAM 引擎
// 7. 未启用事务管理 ❌
// 缺少 @EnableTransactionManagement
// 8. 方法内部 new 对象调用 ❌
@Transactional
public void methodF() {
new InnerService().doSomething(); // 事务不传播
}
class InnerService {
@Transactional
public void doSomething() {
// 事务不生效
}
}
}
8.2 解决方案
java
@Service
public class TransactionSolution {
// 方案1:自注入解决自调用
@Autowired
@Lazy
private TransactionSolution selfProxy;
public void methodA() {
selfProxy.methodB(); // ✅ 通过代理调用
}
@Transactional
public void methodB() { }
// 方案2:正确抛出异常
@Transactional
public void methodC() {
try {
userRepository.save(user);
throw new RuntimeException();
} catch (Exception e) {
// 1. 重新抛出运行时异常
throw new RuntimeException(e);
// 2. 或者设置回滚标记
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
// 方案3:使用编程式事务
private final TransactionTemplate transactionTemplate;
public void methodD() {
transactionTemplate.execute(status -> {
// 复杂的事务逻辑
return null;
});
}
}
九、性能优化与最佳实践
9.1 事务优化建议
java
@Service
public class TransactionOptimization {
// 1. 合理设置只读事务
@Transactional(readOnly = true) // 查询优化
public List<User> findAllActiveUsers() {
return userRepository.findByActiveTrue();
}
// 2. 控制事务时间
@Transactional(timeout = 5) // 5秒超时
public void batchProcess(List<Data> dataList) {
// 分批处理,避免长事务
int batchSize = 100;
for (int i = 0; i < dataList.size(); i += batchSize) {
processBatch(dataList.subList(i, Math.min(i + batchSize, dataList.size())));
}
}
// 3. 合理使用传播行为
@Transactional
public void mainProcess() {
// 主要业务
userRepository.save(user);
// 日志记录使用独立事务
logService.saveLogAsync(user); // REQUIRES_NEW
// 发送消息使用非事务
messageService.sendMessage(user); // NOT_SUPPORTED
}
// 4. 避免大事务
@Transactional
public void bigTransaction() {
// ❌ 不要在事务中做:
// - 网络调用
// - 文件IO
// - 长时间计算
// - 发送邮件/短信
// ✅ 只做数据库操作
userRepository.save(user);
orderRepository.save(order);
}
}
9.2 监控与调试
java
@Component
public class TransactionMonitor {
// 事务事件监听器
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void handleAfterCompletion(TransactionCompletedEvent event) {
System.out.println("事务完成: " + event);
}
// 自定义事务同步器
public void withTransactionSync() {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void beforeCommit(boolean readOnly) {
System.out.println("事务提交前");
}
@Override
public void afterCommit() {
System.out.println("事务提交后");
}
@Override
public void afterCompletion(int status) {
System.out.println("事务完成,状态: " +
(status == STATUS_COMMITTED ? "已提交" : "已回滚"));
}
}
);
}
// 获取当前事务信息
public void printTransactionInfo() {
System.out.println("事务名称: " +
TransactionSynchronizationManager.getCurrentTransactionName());
System.out.println("是否只读: " +
TransactionSynchronizationManager.isCurrentTransactionReadOnly());
System.out.println("是否实际有事务: " +
TransactionSynchronizationManager.isActualTransactionActive());
System.out.println("隔离级别: " +
TransactionSynchronizationManager.getCurrentTransactionIsolationLevel());
}
}
十、实战案例
10.1 分布式事务(Seata)
java
@Service
public class DistributedTransactionService {
// 使用 Seata 的全局事务注解
@GlobalTransactional // Seata 全局事务
@Transactional // 本地事务
public void placeOrder(Order order) {
// 1. 扣减库存
inventoryService.deduct(order.getProductId(), order.getQuantity());
// 2. 创建订单
orderService.create(order);
// 3. 扣减余额
accountService.deduct(order.getUserId(), order.getAmount());
// 如果任何一步失败,所有操作都会回滚
}
}
10.2 链式事务处理
java
@Service
@Slf4j
public class ChainedTransactionService {
private final TransactionTemplate transactionTemplate;
private final UserRepository userRepository;
private final OrderRepository orderRepository;
public void processOrderChain(OrderRequest request) {
// 步骤1:验证用户(独立事务)
User user = transactionTemplate.execute(status -> {
return userRepository.findById(request.getUserId())
.orElseThrow(() -> new RuntimeException("用户不存在"));
});
// 步骤2:创建订单(新事务)
Order order = transactionTemplate.execute(status -> {
Order newOrder = createOrder(request, user);
return orderRepository.save(newOrder);
});
// 步骤3:扣减库存(可能失败)
try {
transactionTemplate.execute(status -> {
deductInventory(order);
return null;
});
} catch (Exception e) {
log.error("库存扣减失败,回滚订单", e);
// 回滚订单(新事务)
transactionTemplate.execute(status -> {
orderRepository.delete(order);
return null;
});
throw e;
}
// 步骤4:发送通知(非事务)
sendNotification(user, order);
}
}
总结
Spring 事务的核心要点:
- 代理机制:Spring 通过 AOP 动态代理实现事务
- 自调用问题 :同一个类内部调用会绕过代理,导致
@Transactional失效 - 传播行为:控制事务如何嵌套和传播
- 隔离级别:控制事务间的可见性和影响
- 声明式 vs 编程式:根据场景选择合适的控制方式
- 最佳实践:避免长事务、合理设置只读、及时释放资源
记住:Spring 事务是基于代理的,理解代理机制是掌握事务的关键。