SpringBoot 编程式事务使用
目录
- 1. 简介
- 2. TransactionTemplate 方式
- 3. TransactionManager 方式
- 4. 事务传播行为
- 5. 事务隔离级别
- 6. 最佳实践
- 7. 常见问题与解决方案
1. 简介
编程式事务管理是通过编写代码来管理事务,相对于声明式事务(@Transactional注解),它提供了更细粒度的事务控制。在 SpringBoot 中,主要有两种实现方式:
- 使用 TransactionTemplate
- 直接使用 TransactionManager
2. TransactionTemplate 方式
TransactionTemplate 是最简单的编程式事务实现方式,它对底层事务 API 进行了封装,使用起来更加便捷。
2.1 基本配置
@Configuration
public class TransactionConfig {
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public TransactionTemplate transactionTemplate() {
TransactionTemplate template = new TransactionTemplate();
template.setTransactionManager(transactionManager);
// 设置默认的事务传播行为
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 设置默认的事务隔离级别
template.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
// 设置默认超时时间
template.setTimeout(30);
return template;
}
}
2.2 基本使用示例
@Service
@Slf4j
public class UserService {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private UserRepository userRepository;
public User createUser(User user) {
// 使用 execute 方法执行有返回值的事务操作
return transactionTemplate.execute(status -> {
try {
User savedUser = userRepository.save(user);
// 模拟其他操作
updateUserProfile(savedUser);
return savedUser;
} catch (Exception e) {
// 手动标记事务回滚
status.setRollbackOnly();
log.error("创建用户失败", e);
throw new RuntimeException("创建用户失败", e);
}
});
}
public void batchCreateUsers(List<User> users) {
// 使用 executeWithoutResult 方法执行无返回值的事务操作
transactionTemplate.executeWithoutResult(status -> {
try {
for (User user : users) {
userRepository.save(user);
}
} catch (Exception e) {
status.setRollbackOnly();
log.error("批量创建用户失败", e);
throw new RuntimeException("批量创建用户失败", e);
}
});
}
}
3. TransactionManager 方式
直接使用 TransactionManager 提供了更细粒度的事务控制,但使用起来相对复杂。
3.1 基本使用示例
@Service
@Slf4j
public class OrderService {
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private OrderRepository orderRepository;
public Order createOrder(Order order) {
// 定义事务属性
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
def.setTimeout(30);
// 获取事务状态
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 执行业务逻辑
Order savedOrder = orderRepository.save(order);
// 处理订单相关的其他操作
processOrderDetails(savedOrder);
// 提交事务
transactionManager.commit(status);
return savedOrder;
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
log.error("创建订单失败", e);
throw new RuntimeException("创建订单失败", e);
}
}
}
3.2 嵌套事务示例
@Service
@Slf4j
public class PaymentService {
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private PaymentRepository paymentRepository;
public void processPayment(Payment payment) {
// 外部事务定义
DefaultTransactionDefinition outerDef = new DefaultTransactionDefinition();
outerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus outerStatus = transactionManager.getTransaction(outerDef);
try {
// 外部事务操作
paymentRepository.save(payment);
// 内部事务定义
DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
TransactionStatus innerStatus = transactionManager.getTransaction(innerDef);
try {
// 执行内部事务操作
processPaymentDetails(payment);
transactionManager.commit(innerStatus);
} catch (Exception e) {
// 回滚内部事务
transactionManager.rollback(innerStatus);
log.error("支付详情处理失败", e);
throw e;
}
// 提交外部事务
transactionManager.commit(outerStatus);
} catch (Exception e) {
// 回滚外部事务
transactionManager.rollback(outerStatus);
log.error("支付处理失败", e);
throw new RuntimeException("支付处理失败", e);
}
}
}
4. 事务传播行为
在编程式事务中,我们可以精确控制事务的传播行为:
@Service
public class TransactionPropagationExample {
@Autowired
private TransactionTemplate transactionTemplate;
public void demonstratePropagation() {
// REQUIRED 传播行为
TransactionTemplate requiredTemplate = new TransactionTemplate(transactionTemplate);
requiredTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// REQUIRES_NEW 传播行为
TransactionTemplate requiresNewTemplate = new TransactionTemplate(transactionTemplate);
requiresNewTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
// 嵌套使用不同的传播行为
requiredTemplate.execute(outerStatus -> {
// 外部事务逻辑
requiresNewTemplate.execute(innerStatus -> {
// 内部事务逻辑(新的事务)
return null;
});
return null;
});
}
}
5. 事务隔离级别
示例展示如何设置不同的事务隔离级别:
@Service
public class TransactionIsolationExample {
@Autowired
private PlatformTransactionManager transactionManager;
public void demonstrateIsolation() {
// 读已提交隔离级别
DefaultTransactionDefinition readCommittedDef = new DefaultTransactionDefinition();
readCommittedDef.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
TransactionStatus readCommittedStatus = transactionManager.getTransaction(readCommittedDef);
try {
// 业务逻辑
transactionManager.commit(readCommittedStatus);
} catch (Exception e) {
transactionManager.rollback(readCommittedStatus);
throw e;
}
// 可重复读隔离级别
DefaultTransactionDefinition repeatableReadDef = new DefaultTransactionDefinition();
repeatableReadDef.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
// ... 类似的事务处理逻辑
}
}
6. 最佳实践
6.1 事务模板封装
创建一个通用的事务处理模板:
@Component
@Slf4j
public class TransactionHelper {
@Autowired
private TransactionTemplate transactionTemplate;
public <T> T executeInTransaction(TransactionCallback<T> action) {
try {
return transactionTemplate.execute(action);
} catch (Exception e) {
log.error("事务执行失败", e);
throw new RuntimeException("事务执行失败", e);
}
}
public void executeInTransactionWithoutResult(Consumer<TransactionStatus> action) {
try {
transactionTemplate.executeWithoutResult(action);
} catch (Exception e) {
log.error("事务执行失败", e);
throw new RuntimeException("事务执行失败", e);
}
}
}
// 使用示例
@Service
public class BusinessService {
@Autowired
private TransactionHelper transactionHelper;
public void doBusiness() {
transactionHelper.executeInTransactionWithoutResult(status -> {
// 业务逻辑
});
}
}
7. 常见问题与解决方案
7.1 事务超时处理
@Service
public class TimeoutExample {
@Autowired
private TransactionTemplate transactionTemplate;
public void handleTimeout() {
TransactionTemplate timeoutTemplate = new TransactionTemplate(transactionTemplate);
timeoutTemplate.setTimeout(5); // 设置5秒超时
try {
timeoutTemplate.execute(status -> {
// 可能超时的业务逻辑
return null;
});
} catch (TransactionTimedOutException e) {
// 处理超时异常
log.error("事务执行超时", e);
throw new RuntimeException("事务执行超时", e);
}
}
}
7.2 异常处理最佳实践
@Service
public class ExceptionHandlingExample {
@Autowired
private TransactionTemplate transactionTemplate;
public void handleExceptions() {
try {
transactionTemplate.execute(status -> {
try {
// 业务逻辑
return null;
} catch (BusinessException e) {
// 业务异常,标记回滚
status.setRollbackOnly();
throw e;
} catch (Exception e) {
// 其他异常,标记回滚
status.setRollbackOnly();
throw new RuntimeException("未预期的错误", e);
}
});
} catch (Exception e) {
// 统一异常处理
handleException(e);
}
}
private void handleException(Exception e) {
if (e instanceof BusinessException) {
// 处理业务异常
log.warn("业务异常: {}", e.getMessage());
} else {
// 处理系统异常
log.error("系统异常", e);
}
throw e;
}
}
虽然编程式事务提供了更细粒度的控制,但在大多数情况下,声明式事务(@Transactional)可能是更好的选择。只有在需要特别精细的事务控制时,才考虑使用编程式事务。