JDBC事务中,我明明只捕获了Exception,为什么当出现Error时也能保证数据正确呢?

新手上路,请多包涵

JDBC事务中,我明明只捕获了Exception,为什么当出现Error时也能保证数据正确呢?

我学习的内容:Java + JDBC + MySQL

代码逻辑很简单:捕获了SQLException:如果出现SQLException就回滚。

但是我发现,即使出现了我没有声明要捕获的ArithmeticException和StackOverflowError,数据仍然没有变化。
就好像是捕获到了我未声明的异常,然后自动回滚了一样。
即使我不用PrepareStatement,而用Statement也是一样的结果。
去看过源码了,也打了断点调试了半天,被淹死在源码里了…
请问这是什么原理呢?

菜鸟一只,恳请大佬赐教。
感谢!

代码如下:

public class Demo06_Transaction {
    public static void main(String[] args) {
        String sql_zhangsan = "UPDATE tb01_jdbc SET balance=balance+? WHERE name=?";
        String sql_lisi = "UPDATE tb01_jdbc SET balance=balance-? WHERE name=?";
        Connection conn = null;
        PreparedStatement pstmt_zhangsan = null;
        PreparedStatement pstmt_lisi = null;

        try {
            conn = JDBCUtils.getConn();

            // 开启事务
            conn.setAutoCommit(false); // 这里逻辑是不设置为自动提交,即手动开启了事务

            // zhangsan增加200
            pstmt_zhangsan = conn.prepareStatement(sql_zhangsan);
            pstmt_zhangsan.setInt(1, 200);
            pstmt_zhangsan.setString(2, "zhangsan");
            pstmt_zhangsan.executeUpdate();
            System.out.println("张三账户里增加了200");

            // 在此处制造ArithmeticException
            int i = 1 / 0;
            // 在此处制造Error,仍然能够保证数据正确 zz 原因不知道
            methodA(); // Exception in thread "main" java.lang.StackOverflowError

            // lisi减少200
            pstmt_lisi = conn.prepareStatement(sql_lisi);
            pstmt_lisi.setInt(1, 200);
            pstmt_lisi.setString(2, "lisi");
            pstmt_lisi.executeUpdate();
            System.out.println("李四账户里减少了200");

            // 提交事务
            conn.commit();
        } catch (SQLException e) { // 
            e.printStackTrace();

            // 出现异常,回滚事务
            try {
                if (conn != null) {
                    conn.rollback();
                    System.out.println("数据已回滚"); // 出现了未声明要获取的StackOverflowError、ArithmeticException时确实没有运行
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            JDBCUtils.close(pstmt_zhangsan, conn);
            JDBCUtils.close(pstmt_lisi, conn);
        }
    }

    // 无限递归制造Error
    private static void methodA() {
        methodA(); // Exception in thread "main" java.lang.StackOverflowError
    }
}
阅读 2.4k
2 个回答

你好,
首先你要知道事务只有提交了才能真正的更新到数据库中

出现原因:你的catch语句并没有抓住那个Error,所以程序运行到methodA就会直接终止,后面所有除了finally代码块中的代码会执行以外,其他都不会被执行,所以事务自然没有提交,所以会回滚到以前的状态

解决办法:你想让事务修改可以把它放到finally代码块中,或者catch Error对象或者Trowable对象,这样可以保证事务能够提交

没有conn.commit();,直接执行finally了,conn.commit();要放在异常上面

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题