Java事务回滚触发的典型案例
运行时异常自动回滚案例
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private InventoryService inventoryService;
@Transactional
public void createOrder(Order order) {
// 1. 保存订单
orderRepository.save(order);
// 2. 扣减库存 - 如果这里抛出运行时异常,订单保存也会回滚
inventoryService.deductStock(order.getProductId(), order.getQuantity());
// 3. 模拟业务异常
if (order.getAmount() > 10000) {
throw new RuntimeException("订单金额超过限制");
}
}
}
检查型异常不会自动回滚
@Service
public class PaymentService {
@Transactional
public void processPayment(Payment payment) throws Exception {
// 1. 扣款
deductFromAccount(payment.getAccountId(), payment.getAmount());
// 2. 这个检查型异常不会触发回滚!
if (payment.getAmount() > 5000) {
throw new Exception("大额支付需要审核");
}
}
// 正确做法:包装成运行时异常或指定rollbackFor
@Transactional(rollbackFor = Exception.class)
public void processPayment2(Payment payment) throws Exception {
// 扣款操作
deductFromAccount(payment.getAccountId(), payment.getAmount());
if (payment.getAmount() > 5000) {
throw new Exception("大额支付需要审核");
}
}
}
嵌套事务回滚案例
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private LogService logService;
@Transactional
public void registerUser(User user) {
// 1. 保存用户
userRepository.save(user);
// 2. 记录日志 - 事务传播行为REQUIRES_NEW
try {
logService.saveLog("用户注册: " + user.getName());
} catch (Exception e) {
// 日志失败不影响用户注册
System.out.println("日志记录失败,但用户注册成功");
}
// 3. 发送欢迎邮件
sendWelcomeEmail(user);
}
}
@Service
public class LogService {
@Autowired
private LogRepository logRepository;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(String message) {
logRepository.save(new Log(message));
// 模拟日志保存失败
if (message.contains("错误")) {
throw new RuntimeException("日志保存异常");
}
}
}
编程式事务回滚
@Service
public class AccountService {
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private AccountRepository accountRepository;
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
// 定义事务
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
def.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 1. 扣款
Account fromAccount = accountRepository.findById(fromId).orElseThrow();
fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
accountRepository.save(fromAccount);
// 2. 检查余额
if (fromAccount.getBalance().compareTo(BigDecimal.ZERO) < 0) {
throw new RuntimeException("余额不足");
}
// 3. 入账
Account toAccount = accountRepository.findById(toId).orElseThrow();
toAccount.setBalance(toAccount.getBalance().add(amount));
accountRepository.save(toAccount);
// 提交事务
transactionManager.commit(status);
} catch (RuntimeException e) {
// 回滚事务
transactionManager.rollback(status);
throw e;
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
throw new RuntimeException("转账失败", e);
}
}
}
使用TransactionAspectSupport手动回滚
@Service
public class DocumentService {
@Transactional
public void uploadDocument(Document doc) {
// 1. 保存文档
documentRepository.save(doc);
// 2. 上传到文件服务器
boolean uploadSuccess = fileService.upload(doc.getContent(), doc.getPath());
if (!uploadSuccess) {
// 手动回滚,同时保留异常信息
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw new RuntimeException("文件上传失败,事务回滚");
}
// 3. 更新文档状态
doc.setStatus("UPLOADED");
documentRepository.save(doc);
}
}
常见的触发回滚场景
@Service
public class BatchProcessService {
@Transactional
public void batchUpdate(List<Entity> entities) {
for (int i = 0; i < entities.size(); i++) {
Entity entity = entities.get(i);
try {
// 处理每个实体
processSingleEntity(entity);
} catch (DataIntegrityViolationException e) {
// 数据完整性违规 - 自动回滚
throw e;
} catch (OptimisticLockException e) {
// 乐观锁异常 - 自动回滚
throw e;
} catch (Exception e) {
// 处理单个失败,不影响其他
log.error("处理第{}个实体失败: {}", i, e.getMessage());
}
}
}
private void processSingleEntity(Entity entity) {
// 可能抛出各种异常
}
}
- 默认行为:只有
RuntimeException和Error及其子类会触发回滚 - 检查型异常:默认不回滚,需通过
rollbackFor指定 - 嵌套事务:
REQUIRES_NEW会暂停当前事务,独立异常不影响外层 - 手动回滚:使用
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() - 编程式事务:通过
PlatformTransactionManager精确控制
这些案例覆盖了实际开发中最常见的事务回滚场景。
