Java代码回滚案例

wen java案例 1

本文目录导读:

Java代码回滚案例

  1. 数据库事务回滚案例
  2. 代码版本回滚工具类
  3. Spring Boot 事务管理完整案例
  4. 使用AOP实现自定义回滚逻辑
  5. 最佳实践建议

我来为您提供一个完整的Java代码回滚案例,包含数据库事务回滚和代码版本回滚两个层面。

数据库事务回滚案例

场景:银行转账系统

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class BankTransferService {
    private static final String DB_URL = "jdbc:mysql://localhost:3306/bank";
    private static final String USER = "root";
    private static final String PASSWORD = "password";
    /**
     * 转账操作(带事务回滚)
     * @param fromAccount 转出账户
     * @param toAccount 转入账户
     * @param amount 转账金额
     */
    public void transfer(String fromAccount, String toAccount, double amount) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            // 1. 获取数据库连接
            conn = DriverManager.getConnection(DB_URL, USER, PASSWORD);
            // 2. 关闭自动提交,开启事务
            conn.setAutoCommit(false);
            // 3. 扣款操作
            String deductSql = "UPDATE accounts SET balance = balance - ? WHERE account_no = ?";
            pstmt = conn.prepareStatement(deductSql);
            pstmt.setDouble(1, amount);
            pstmt.setString(2, fromAccount);
            int deductResult = pstmt.executeUpdate();
            if (deductResult == 0) {
                throw new SQLException("转出账户不存在");
            }
            // 4. 检查余额是否足够
            String checkSql = "SELECT balance FROM accounts WHERE account_no = ?";
            pstmt = conn.prepareStatement(checkSql);
            pstmt.setString(1, fromAccount);
            var rs = pstmt.executeQuery();
            if (rs.next() && rs.getDouble("balance") < 0) {
                throw new SQLException("余额不足");
            }
            // 5. 入账操作
            String creditSql = "UPDATE accounts SET balance = balance + ? WHERE account_no = ?";
            pstmt = conn.prepareStatement(creditSql);
            pstmt.setDouble(1, amount);
            pstmt.setString(2, toAccount);
            int creditResult = pstmt.executeUpdate();
            if (creditResult == 0) {
                throw new SQLException("转入账户不存在");
            }
            // 6. 记录交易日志
            String insertLogSql = "INSERT INTO transaction_log (from_account, to_account, amount, status) VALUES (?, ?, ?, ?)";
            pstmt = conn.prepareStatement(insertLogSql);
            pstmt.setString(1, fromAccount);
            pstmt.setString(2, toAccount);
            pstmt.setDouble(3, amount);
            pstmt.setString(4, "SUCCESS");
            pstmt.executeUpdate();
            // 7. 事务提交
            conn.commit();
            System.out.println("转账成功!");
        } catch (SQLException e) {
            // 8. 发生异常,执行回滚
            if (conn != null) {
                try {
                    conn.rollback();
                    System.out.println("转账失败,已回滚事务!");
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            // 9. 释放资源
            try {
                if (pstmt != null) pstmt.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

使用Spring @Transactional注解的事务回滚

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
    @Transactional(rollbackFor = RuntimeException.class)
    public void createOrder(Order order) {
        try {
            // 1. 创建订单
            orderDao.insert(order);
            // 2. 扣减库存
            int result = productDao.deductStock(order.getProductId(), order.getQuantity());
            if (result == 0) {
                throw new RuntimeException("库存不足");
            }
            // 3. 其他业务操作
            userDao.updateUserScore(order.getUserId(), order.getTotalAmount() * 10);
        } catch (Exception e) {
            // Spring会自动回滚事务
            throw new RuntimeException("创建订单失败:" + e.getMessage());
        }
    }
    /**
     * 手动控制回滚
     */
    @Transactional(rollbackFor = Exception.class)
    public void manualRollback(Order order) {
        // 使用TransactionAspectSupport手动回滚
        try {
            // 业务逻辑
            processOrder(order);
        } catch (Exception e) {
            // 主动触发回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw e;
        }
    }
}

代码版本回滚工具类

简单的代码版本管理器

import java.util.Stack;
import java.util.HashMap;
import java.util.Map;
public class CodeVersionManager {
    // 存储代码快照
    private static Map<String, Stack<CodeSnapshot>> versionStacks = new HashMap<>();
    // 代码快照类
    private static class CodeSnapshot {
        private String version;
        private String codeContent;
        private long timestamp;
        public CodeSnapshot(String version, String codeContent) {
            this.version = version;
            this.codeContent = codeContent;
            this.timestamp = System.currentTimeMillis();
        }
        public String getVersion() {
            return version;
        }
        public String getCodeContent() {
            return codeContent;
        }
        public long getTimestamp() {
            return timestamp;
        }
    }
    /**
     * 保存代码快照
     */
    public static void saveSnapshot(String module, String filePath, String codeContent) {
        String key = module + ":" + filePath;
        versionStacks.computeIfAbsent(key, k -> new Stack<>());
        String version = "v" + (versionStacks.get(key).size() + 1);
        versionStacks.get(key).push(new CodeSnapshot(version, codeContent));
        System.out.println("已保存快照,版本号:" + version);
    }
    /**
     * 回滚到上一个版本
     */
    public static String rollback(String module, String filePath) {
        String key = module + ":" + filePath;
        Stack<CodeSnapshot> stack = versionStacks.get(key);
        if (stack == null || stack.isEmpty()) {
            return null;
        }
        CodeSnapshot snapshot = stack.pop();
        System.out.println("回滚到版本:" + snapshot.getVersion() + ",时间:" + 
                          new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date(snapshot.getTimestamp())));
        return snapshot.getCodeContent();
    }
    /**
     * 查看历史版本
     */
    public static void showHistory(String module, String filePath) {
        String key = module + ":" + filePath;
        Stack<CodeSnapshot> stack = versionStacks.get(key);
        if (stack != null && !stack.isEmpty()) {
            System.out.println("历史版本列表:");
            for (CodeSnapshot snapshot : stack) {
                System.out.println("- " + snapshot.getVersion());
            }
        } else {
            System.out.println("该文件没有历史版本");
        }
    }
}

使用示例

public class VersionControlExample {
    public static void main(String[] args) {
        // 模拟代码文件的版本控制
        String module = "user-service";
        String filePath = "UserService.java";
        // 保存不同版本的代码
        CodeVersionManager.saveSnapshot(module, filePath, 
            "class UserService {\n    public void createUser() {\n        // v1 实现\n    }\n}");
        CodeVersionManager.saveSnapshot(module, filePath,
            "class UserService {\n    public void createUser() {\n        // v2 实现(包含bug)\n    }\n}");
        CodeVersionManager.saveSnapshot(module, filePath,
            "class UserService {\n    public void createUser() {\n        // v3 实现\n    }\n}");
        // 查看版本历史
        CodeVersionManager.showHistory(module, filePath);
        // 发现v3有bug,回滚到v2
        String rolledBackCode = CodeVersionManager.rollback(module, filePath);
        System.out.println("回滚后的代码:\n" + rolledBackCode);
        // 再回滚到v1
        String rollbackToV1 = CodeVersionManager.rollback(module, filePath);
        System.out.println("再次回滚后的代码:\n" + rollbackToV1);
    }
}

Spring Boot 事务管理完整案例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private AccountRepository accountRepository;
    /**
     * 下单并支付(包含完整事务)
     */
    @Transactional(
        propagation = Propagation.REQUIRED,
        isolation = Isolation.READ_COMMITTED,
        rollbackFor = Exception.class
    )
    public String placeOrderAndPay(Order order, PaymentInfo paymentInfo) {
        try {
            // 1. 验证用户和商品
            validateOrder(order);
            // 2. 创建订单(状态:待支付)
            Order savedOrder = orderRepository.save(order);
            // 3. 扣减库存
            deductStock(order.getProductId(), order.getQuantity());
            // 4. 执行支付
            boolean paymentResult = processPayment(savedOrder, paymentInfo);
            if (!paymentResult) {
                throw new PaymentException("支付失败");
            }
            // 5. 更新订单状态为已支付
            savedOrder.setStatus("PAID");
            orderRepository.save(savedOrder);
            // 6. 记录操作日志
            logOrder(savedOrder);
            // 返回订单号
            return savedOrder.getOrderNo();
        } catch (PaymentException e) {
            // 当发生特定异常时回滚事务
            throw new TransactionException("订单处理失败,事务已回滚", e);
        } catch (Exception e) {
            // 其他异常也会触发回滚
            throw new TransactionException("系统异常,事务已回滚", e);
        }
    }
    /**
     * 部分提交示例
     */
    @Transactional
    public void partialCommitExample() {
        // REQUIRED: 会加入到当前事务
        helperMethod1();
        // REQUIRES_NEW: 会开启新事务
        helperMethod2();
        // NESTED: 如果有事务就嵌套,否则开启新事务
        helperMethod3();
    }
    private void validateOrder(Order order) {
        // 验证逻辑
    }
    private void deductStock(Long productId, int quantity) {
        // 扣减库存逻辑
    }
    private boolean processPayment(Order order, PaymentInfo paymentInfo) {
        // 支付处理逻辑
        return true;
    }
    private void logOrder(Order order) {
        // 日志记录
    }
    // 自定义异常类
    static class PaymentException extends RuntimeException {
        public PaymentException(String message) {
            super(message);
        }
    }
    static class TransactionException extends RuntimeException {
        public TransactionException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}

使用AOP实现自定义回滚逻辑

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
@Aspect
@Component
public class TransactionAdvice {
    /**
     * 自定义事务管理切面
     */
    @Around("@annotation(customTransaction)")
    public Object handleTransaction(ProceedingJoinPoint joinPoint, CustomTransaction customTransaction) 
            throws Throwable {
        Object result = null;
        boolean isSuccessful = true;
        try {
            // 前置处理
            System.out.println("开启事务");
            // 执行目标方法
            result = joinPoint.proceed();
            // 后置处理(成功)
            System.out.println("事务提交成功");
        } catch (Exception e) {
            isSuccessful = false;
            // 回滚处理
            if (customTransaction.rollbackOnException()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                System.out.println("事务回滚");
            }
            throw e;
        } finally {
            // 无论成功失败都会执行
            System.out.println("是否成功:" + isSuccessful);
        }
        return result;
    }
    // 自定义注解
    @interface CustomTransaction {
        boolean rollbackOnException() default true;
    }
}

最佳实践建议

  1. 事务回滚

    • 使用Spring的声明式事务(@Transactional)而非编程式事务
    • 合理设置rollbackFor属性
    • 避免事务方法内try-catch吞掉异常
  2. 代码回滚

    • 使用Git等版本控制工具
    • 保持提交的原子性
    • 定期创建tag或release
  3. 监控与日志

    • 记录事务边界日志
    • 实现失败自动回滚机制
    • 设置合理的超时时间
  4. 性能优化

    • 事务范围要尽量小
    • 合理使用读写分离
    • 避免长事务

这个案例展示了Java中代码回滚的完整实现,从数据库事务到代码版本管理都覆盖到了。

抱歉,评论功能暂时关闭!