一、什么是 TransactionManager
TransactionManage 是Java事务管理的核心接口,负责协调和管理事务的生命周期。
核心接口定义
PlatformTransactionManager是 Spring 事务抽象的核心接口,它采用了 策略模式(Strategy Pattern),为不同的事务管理技术提供了统一的抽象层。
java
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.transaction;
import org.springframework.lang.Nullable;
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
1. getTransaction() - 获取事务
java
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
参数:TransactionDefinition
定义了事务的所有属性:
java
public interface TransactionDefinition {
// 传播行为
int getPropagationBehavior();
// 隔离级别
int getIsolationLevel();
// 超时时间(秒)
int getTimeout();
// 是否只读
boolean isReadOnly();
// 事务名称
@Nullable
String getName();
}
返回值:TransactionStatus
表示当前事务的状态:
java
public interface TransactionStatus extends TransactionExecution, SavepointManager {
// 是否是新事务
boolean isNewTransaction();
// 是否有保存点
boolean hasSavepoint();
// 设置为仅回滚
void setRollbackOnly();
// 是否标记为仅回滚
boolean isRollbackOnly();
// 刷新状态
void flush();
// 是否已完成
boolean isCompleted();
}
2. commit() - 提交事务
java
void commit(TransactionStatus status) throws TransactionException;
提交逻辑:
java
public void commit(TransactionStatus status) throws TransactionException {
// 1. 检查事务是否已完成
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
// 2. 检查是否标记为回滚
if (status.isRollbackOnly()) {
// 即使调用commit,也要回滚
rollback(status);
return;
}
// 3. 执行提交
try {
doCommit(status);
} catch (TransactionException ex) {
// 提交失败尝试回滚
try {
doRollback(status);
} catch (RuntimeException | Error rbex) {
logger.error("Commit exception overridden by rollback exception", ex);
throw rbex;
}
throw ex;
} finally {
cleanupAfterCompletion(status);
}
}
3. rollback() - 回滚事务
java
void rollback(TransactionStatus status) throws TransactionException;
回滚逻辑:
java
public void rollback(TransactionStatus status) throws TransactionException {
// 1. 检查事务是否已完成
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
// 2. 执行回滚
try {
doRollback(status);
} catch (RuntimeException | Error ex) {
throw ex;
} finally {
cleanupAfterCompletion(status);
}
}
二、主要实现类
1. DataSourceTransactionManager(最常用)
java
// Spring JDBC事务管理器
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
适用场景:单数据源JDBC操作
2. JpaTransactionManager
java
// JPA/Hibernate事务管理器
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
3. JtaTransactionManager
java
// 分布式事务管理器(XA协议)
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager"/>
</bean>
三、核心配置
基于XML配置
xml
<!-- 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="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</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>
基于Java配置
java
@Configuration
@EnableTransactionManagement // 启用注解事务
public class TransactionConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
四、事务传播行为(Propagation)
| 传播行为 | 说明 | 使用场景 |
|---|---|---|
| REQUIRED(默认) | 如果当前没有事务,就新建一个事务;如果已存在,就加入 | 通用业务方法 |
| REQUIRES_NEW | 新建事务,如果当前存在事务,则挂起当前事务 | 日志记录、独立操作 |
| SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行 | 查询方法 |
| NOT_SUPPORTED | 以非事务方式执行,如果当前存在事务,则挂起 | 调用外部服务 |
| NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常 | 必须非事务执行 |
| MANDATORY | 使用当前事务,如果当前没有事务,则抛出异常 | 必须存在事务 |
| NESTED | 如果当前存在事务,则在嵌套事务内执行 | 复杂业务的分步操作 |
示例代码:
java
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder(Order order) {
// 主业务逻辑
orderDao.save(order);
// 需要独立事务的操作
try {
logService.saveLog(order); // REQUIRES_NEW
} catch (Exception e) {
// 日志失败不影响主事务
}
}
}
@Service
public class LogService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(Order order) {
// 独立事务,即使主事务回滚,日志也会保存
logDao.save(createLog(order));
}
}
五、事务隔离级别(Isolation)
| 隔离级别 | 说明 | 问题解决 |
|---|---|---|
| DEFAULT | 使用数据库默认隔离级别 | - |
| READ_UNCOMMITTED | 读未提交 | 脏读、不可重复读、幻读 |
| READ_COMMITTED | 读已提交(Oracle默认) | 解决脏读 |
| REPEATABLE_READ | 可重复读(MySQL默认) | 解决脏读、不可重复读 |
| SERIALIZABLE | 串行化 | 解决所有并发问题 |
示例配置:
java
@Transactional(isolation = Isolation.READ_COMMITTED)
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
// 需要较高隔离级别的金融操作
accountDao.subtractBalance(fromId, amount);
accountDao.addBalance(toId, amount);
}
六、编程式事务管理
使用 TransactionTemplate
java
@Service
public class UserService {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private UserRepository userRepository;
public void batchUpdateUsers(List<User> users) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
for (User user : users) {
userRepository.update(user);
// 每100条提交一次
if (user.getId() % 100 == 0) {
// 手动刷新,但事务仍整体提交
}
}
} catch (Exception e) {
status.setRollbackOnly(); // 标记回滚
throw e;
}
}
});
}
}
使用 PlatformTransactionManager
java
@Service
public class ManualTransactionService {
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private UserRepository userRepository;
public void complexOperation() {
// 定义事务属性
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
def.setTimeout(30); // 30秒超时
// 开启事务
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 业务操作
userRepository.save(user1);
userRepository.save(user2);
// 提交事务
transactionManager.commit(status);
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
throw e;
}
}
}
七、TransactionManager 常见问题
问题1:长事务锁表/死锁
场景:
java
@Transactional
public void processLargeOrder(Order order) {
// 1. 查询并锁定库存记录(行锁/表锁)
Inventory inventory = inventoryDao.selectForUpdate(order.getProductId());
// 2. 复杂计算逻辑(耗时5秒)
BigDecimal amount = complexCalculation(order);
// 3. 调用外部系统(网络IO,耗时10秒)
paymentService.charge(order.getUserId(), amount);
// 4. 更新库存
inventory.setQuantity(inventory.getQuantity() - order.getQuantity());
inventoryDao.update(inventory);
}
问题:事务持有锁25秒,其他线程被阻塞,导致死锁或超时
解决方案:
java
@Service
public class OrderServiceV2 {
@Autowired
private TransactionTemplate transactionTemplate;
// 方案1:拆分事务,尽早释放锁
public void processLargeOrder(Order order) {
// 第一步:快速锁定并扣减库存(短事务)
boolean inventorySuccess = transactionTemplate.execute(status -> {
Inventory inventory = inventoryDao.selectForUpdate(order.getProductId());
if (inventory.getQuantity() < order.getQuantity()) {
status.setRollbackOnly();
return false;
}
inventoryDao.deductQuantity(order.getProductId(), order.getQuantity());
return true;
});
if (!inventorySuccess) {
throw new InventoryException("库存不足");
}
// 第二步:复杂计算(无事务)
BigDecimal amount = complexCalculation(order);
// 第三步:支付(独立事务)
try {
paymentService.charge(order.getUserId(), amount);
} catch (Exception e) {
// 支付失败,恢复库存(需要幂等)
restoreInventory(order.getProductId(), order.getQuantity());
throw e;
}
// 第四步:记录日志等非核心操作
asyncLogService.logOrder(order, amount);
}
// 方案2:使用乐观锁
@Transactional
public void processOrderWithOptimisticLock(Order order) {
// 使用版本号控制
int rows = inventoryDao.deductWithVersion(
order.getProductId(),
order.getQuantity(),
currentVersion);
if (rows == 0) {
// 版本冲突,重试或抛异常
throw new OptimisticLockException("库存已被修改,请重试");
}
// 后续操作...
}
}
问题2:连接池耗尽
场景:
java
@Transactional
public void batchProcess(List<Data> dataList) {
for (Data data : dataList) {
// 每个循环都调用其他服务方法(开启新事务传播)
someService.process(data);
}
// 事务持有连接直到循环结束
}
解决方案:
java
@Service
public class BatchProcessor {
@Autowired
private DataService dataService;
// 方案1:非事务批量处理
@Transactional(propagation = Propagation.NOT_SUPPORTED) // 挂起事务
public void batchProcess(List<Data> dataList) {
int batchSize = 100;
for (int i = 0; i < dataList.size(); i += batchSize) {
List<Data> batch = dataList.subList(i, Math.min(i + batchSize, dataList.size()));
// 每个批次独立事务
processBatch(batch);
// 释放连接
EntityManagerHelper.clear(); // JPA清理上下文
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 30)
private void processBatch(List<Data> batch) {
for (Data data : batch) {
dataService.process(data);
}
}
// 方案2:使用连接泄漏检测
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setMaximumPoolSize(20);
ds.setLeakDetectionThreshold(10000); // 10秒连接泄漏检测
ds.setConnectionTimeout(30000); // 30秒连接超时
return ds;
}
}
}
问题3:分布式事务不一致
场景:
java
@Transactional
public void placeDistributedOrder(Order order) {
// 本地数据库
orderDao.save(order);
// 远程服务调用
inventoryService.deduct(order.getProductId(), order.getQuantity()); // HTTP调用
// 另一个远程服务
couponService.useCoupon(order.getCouponId()); // RPC调用
}
解决方案:
java
@Service
public class DistributedOrderService {
// 方案1:最终一致性 + 本地消息表
@Transactional
public void placeOrderWithLocalMessage(Order order) {
// 1. 保存订单(本地事务)
orderDao.save(order);
// 2. 记录本地消息(同一个事务)
Message message = new Message();
message.setType("INVENTORY_DEDUCT");
message.setContent(JSON.toJSONString(order));
messageDao.save(message);
// 3. 发送消息到MQ(事务提交后)
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void afterCommit() {
// 异步发送消息
mqProducer.send(message);
}
}
);
}
// 方案2:TCC模式
public void placeOrderWithTCC(Order order) {
// Try阶段
inventoryService.tryDeduct(order.getProductId(), order.getQuantity());
couponService.tryUse(order.getCouponId());
try {
// Confirm阶段
orderDao.save(order);
inventoryService.confirmDeduct(order.getProductId());
couponService.confirmUse(order.getCouponId());
} catch (Exception e) {
// Cancel阶段
inventoryService.cancelDeduct(order.getProductId());
couponService.cancelUse(order.getCouponId());
throw e;
}
}
// 方案3:使用Seata分布式事务
@GlobalTransactional // Seata注解
public void placeOrderWithSeata(Order order) {
orderDao.save(order);
inventoryFeignClient.deduct(order.getProductId(), order.getQuantity());
couponFeignClient.use(order.getCouponId());
}
}
问题4:部分更新问题
场景:
java
@Transactional
public void updateUserProfile(User user) {
userDao.updateBasicInfo(user); // 成功
userDao.updatePreferences(user); // 失败,但第一个更新已提交?
userDao.updateStatistics(user); // 不会执行
}
解决方案:
java
@Service
public class UserService {
// 方案1:使用声明式事务,默认会全部回滚
@Transactional(rollbackFor = Exception.class)
public void updateUserProfile(User user) {
// 所有操作在一个事务中
}
// 方案2:手动控制保存点
@Transactional
public void updateUserWithSavepoint(User user) {
Object savepoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
try {
userDao.updateBasicInfo(user);
} catch (Exception e) {
// 只回滚到保存点
TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savepoint);
log.warn("基本信息更新失败,已回滚", e);
}
try {
userDao.updatePreferences(user);
} catch (Exception e) {
log.error("偏好设置更新失败,但基本信息已提交", e);
// 可以继续执行其他操作
}
// 继续执行...
}
// 方案3:使用补偿事务
public void updateUserWithCompensation(User user) {
// 记录原始状态
User original = userDao.findById(user.getId());
try {
userDao.updateBasicInfo(user);
userDao.updatePreferences(user);
userDao.updateStatistics(user);
} catch (Exception e) {
// 执行补偿操作
compensateUserUpdate(original);
throw e;
}
}
}
问题5:事务注解滥用
场景:
java
@Service
public class ProductService {
@Transactional // ❌ 滥用:查询方法不需要事务
public Product getProduct(Long id) {
return productDao.findById(id);
}
@Transactional // ❌ 滥用:简单操作过度设计
public void updateProductName(Long id, String name) {
productDao.updateName(id, name);
}
@Transactional(propagation = Propagation.REQUIRES_NEW) // ❌ 不必要的独立事务
public void logAccess(Long productId) {
accessLogDao.log(productId);
}
}
解决方案:
java
@Service
public class ProductServiceOptimized {
// ✅ 正确:查询方法使用SUPPORTS
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public Product getProduct(Long id) {
return productDao.findById(id);
}
// ✅ 正确:简单更新使用默认事务
@Transactional
public void updateProductName(Long id, String name) {
productDao.updateName(id, name);
}
// ✅ 正确:日志记录不需要事务,或使用NOT_SUPPORTED
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void logAccess(Long productId) {
// 如果日志失败,不应影响主业务
try {
accessLogDao.log(productId);
} catch (Exception e) {
log.error("记录访问日志失败", e);
}
}
// ✅ 事务配置规范
@Transactional(
propagation = Propagation.REQUIRED, // 默认
isolation = Isolation.READ_COMMITTED, // 明确隔离级别
timeout = 30, // 设置超时
rollbackFor = {BusinessException.class, RuntimeException.class}, // 明确回滚异常
readOnly = false
)
public void complexBusiness() {
// 复杂业务逻辑
}
}
问题6:循环依赖与自调用
场景:
java
@Service
public class OrderService {
@Autowired
private OrderService orderService; // 循环依赖
@Transactional
public void placeOrder(Order order) {
validateOrder(order); // 事务生效
processPayment(order); // 事务生效
updateInventory(order); // 事务生效
sendNotification(order); // ❌ 事务失效(自调用)
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void sendNotification(Order order) {
// AOP代理失效,事务注解无效
notificationDao.save(new Notification(order));
}
}
解决方案:
java
@Service
public class OrderServiceFixed {
@Autowired
private NotificationService notificationService; // 拆分为独立服务
@Autowired
private OrderService selfProxy; // 自注入解决自调用
@Transactional
public void placeOrder(Order order) {
validateOrder(order);
processPayment(order);
updateInventory(order);
// 方案1:调用其他服务
notificationService.sendOrderNotification(order);
// 方案2:通过代理调用自身方法
selfProxy.sendNotificationInternal(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendNotificationInternal(Order order) {
notificationDao.save(new Notification(order));
}
}
@Service
public class NotificationService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendOrderNotification(Order order) {
notificationDao.save(new Notification(order));
}
}
// 方案3:使用编程式事务
@Service
public class OrderServiceProgrammatic {
@Autowired
private TransactionTemplate transactionTemplate;
public void placeOrder(Order order) {
// 主事务
transactionTemplate.execute(status -> {
validateOrder(order);
processPayment(order);
updateInventory(order);
return null;
});
// 独立事务发送通知
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
notificationDao.save(new Notification(order));
}
});
}
}
问题7:事务难以监控和排查
解决方案:
java
@Aspect
@Component
@Slf4j
public class TransactionMonitorAspect {
private ThreadLocal<TransactionContext> context = new ThreadLocal<>();
@Around("@annotation(transactional)")
public Object monitorTransaction(ProceedingJoinPoint joinPoint,
Transactional transactional) throws Throwable {
TransactionContext ctx = new TransactionContext();
ctx.setStartTime(System.currentTimeMillis());
ctx.setMethod(joinPoint.getSignature().toShortString());
ctx.setPropagation(transactional.propagation());
context.set(ctx);
MDC.put("txId", UUID.randomUUID().toString());
log.info("事务开始: {}, 传播行为: {}", ctx.getMethod(), ctx.getPropagation());
try {
Object result = joinPoint.proceed();
ctx.setSuccess(true);
return result;
} catch (Exception e) {
ctx.setSuccess(false);
ctx.setError(e.getMessage());
// 检查是否需要回滚
for (Class<?> rollbackFor : transactional.rollbackFor()) {
if (rollbackFor.isAssignableFrom(e.getClass())) {
log.warn("事务回滚: {}, 原因: {}", ctx.getMethod(), e.getMessage());
throw e;
}
}
log.info("事务提交(异常但无需回滚): {}, 异常: {}", ctx.getMethod(), e.getMessage());
throw e;
} finally {
ctx.setEndTime(System.currentTimeMillis());
long duration = ctx.getEndTime() - ctx.getStartTime();
if (duration > 5000) { // 5秒以上记录警告
log.warn("长事务警告: {}, 耗时: {}ms", ctx.getMethod(), duration);
}
// 发送到监控系统
Metrics.counter("transaction.count",
"method", ctx.getMethod(),
"success", String.valueOf(ctx.isSuccess()),
"duration", String.valueOf(duration)
).increment();
context.remove();
MDC.remove("txId");
}
}
@Data
private static class TransactionContext {
private String method;
private Propagation propagation;
private long startTime;
private long endTime;
private boolean success;
private String error;
}
}