本文目录导读:

在Java中实现回滚主要有以下几种方式,具体取决于你使用的技术栈:
Spring声明式事务(最常用)
使用 @Transactional 注解
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private AccountRepository accountRepository;
@Transactional(rollbackFor = Exception.class) // 指定回滚异常类型
public void createUserAndAccount(User user, Account account) {
// 第一个操作
userRepository.save(user);
// 如果这里发生异常,第一个操作会自动回滚
if (user.getAge() < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
// 第二个操作
accountRepository.save(account);
}
}
手动控制回滚
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
try {
// 执行业务逻辑
saveOrder(order);
updateInventory(order);
deductBalance(order);
} catch (Exception e) {
// 手动触发回滚
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
throw e;
}
}
}
JDBC事务管理
原生JDBC实现
public class JdbcTransactionDemo {
public void transferMoney(Connection conn,
int fromAccount,
int toAccount,
double amount) throws SQLException {
conn.setAutoCommit(false); // 关闭自动提交
try {
// 扣款操作
String debitSql = "UPDATE accounts SET balance = balance - ? WHERE id = ?";
try (PreparedStatement pstmt = conn.prepareStatement(debitSql)) {
pstmt.setDouble(1, amount);
pstmt.setInt(2, fromAccount);
pstmt.executeUpdate();
}
// 如果余额不足,抛异常触发回滚
if (checkBalance(conn, fromAccount) < 0) {
throw new SQLException("Insufficient balance");
}
// 存款操作
String creditSql = "UPDATE accounts SET balance = balance + ? WHERE id = ?";
try (PreparedStatement pstmt = conn.prepareStatement(creditSql)) {
pstmt.setDouble(1, amount);
pstmt.setInt(2, toAccount);
pstmt.executeUpdate();
}
// 提交事务
conn.commit();
} catch (SQLException e) {
// 发生异常时回滚
conn.rollback();
throw e;
} finally {
conn.setAutoCommit(true); // 恢复自动提交
}
}
private double checkBalance(Connection conn, int accountId) throws SQLException {
// 查询余额的逻辑
return 1000.0; // 简化示例
}
}
Spring编程式事务管理
@Service
public class TransactionTemplateDemo {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private SomeRepository repository;
public void doComplexOperation() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
// 业务操作1
repository.saveEntity1(entity1);
// 业务操作2(可能失败)
repository.saveEntity2(entity2);
} catch (Exception e) {
// 设置事务回滚
status.setRollbackOnly();
throw e;
}
}
});
}
}
自定义回滚逻辑(补偿机制)
适用于分布式系统或无法使用数据库事务的场景:
@Component
public class CompensatingTransactionDemo {
@Autowired
private ServiceA serviceA;
@Autowired
private ServiceB serviceB;
public void executeWithCompensation() {
boolean stepASuccess = false;
boolean stepBSuccess = false;
try {
// 执行步骤A
serviceA.doStepA();
stepASuccess = true;
// 执行步骤B
serviceB.doStepB();
stepBSuccess = true;
} catch (Exception e) {
log.error("Operation failed, starting compensation...");
// 执行补偿操作
if (stepASuccess) {
compensateStepA();
}
if (stepBSuccess) {
compensateStepB();
}
throw new RuntimeException("Transaction failed, compensated", e);
}
}
private void compensateStepA() {
serviceA.undoStepA();
}
private void compensateStepB() {
serviceB.undoStepB();
}
}
配置注意事项
Spring Boot 配置
spring:
datasource:
# 数据源配置
url: jdbc:mysql://localhost:3306/test
username: root
password: password
# 事务管理配置
transaction:
rollback-on-commit-failure: true
default-timeout: 30
@Transactional 注解的关键属性
@Transactional(
propagation = Propagation.REQUIRED, // 事务传播行为
isolation = Isolation.READ_COMMITTED, // 隔离级别
timeout = 30, // 超时时间(秒)
rollbackFor = {Exception.class, RuntimeException.class}, // 触发回滚的异常
noRollbackFor = {BusinessException.class} // 不触发回滚的异常
)
最佳实践
-
选择合适的回滚策略:
- 单体应用:使用声明式事务
- 分布式系统:使用Saga模式或补偿事务
-
明确回滚范围:
@Transactional(rollbackFor = Exception.class) // 默认只回滚RuntimeException,这里设置回滚所有异常
-
避免在事务中捕获异常:
// ❌ 错误示例:捕获了异常导致不回滚 @Transactional public void badExample() { try { saveData(); } catch (Exception e) { log.error("Error", e); // 异常被吃掉,事务不会回滚 } } // ✅ 正确示例:让异常传播出去 @Transactional public void goodExample() { saveData(); } -
数据库引擎选择:
- MySQL使用InnoDB(支持事务)
- 避免使用MyISAM(不支持事务)
选择合适的回滚方式取决于你的应用架构、数据一致性要求以及是否支持分布式事务。