1. 程式人生 > 其它 >【JDBC】筆記(4)--- JDBC 事務自動提交機制;賬戶轉賬演示事務程式碼(bug版+修正版)

【JDBC】筆記(4)--- JDBC 事務自動提交機制;賬戶轉賬演示事務程式碼(bug版+修正版)

但是在實際的業務中,通常是多條 DML語句 聯合完成的,那麼就必須保證這些 DML語句 在同一個事務中同時成功或失敗......

楔子:

JDBC 的事務預設是自動提交的:

只要執行一條 DML語句,則自動提交一次。但是在實際的業務中,通常是多條 DML語句 聯合完成的,那麼就必須保證這些 DML語句 在同一個事務中同時成功或失敗!!!

否則這會是一個非常嚴重的bug!!!


/*
1、功能:實現轉賬功能(bug版)
2、需求:演示一下 JDBC事務 預設自動提交存在的隱患
3、t_act:(原表)
+-------+---------+
| actno | balance |
+-------+---------+
| 5566 | 1000.00 |
| 1314 | 0.00 |
+-------+---------+

*/

import java.sql.*;

/**
 *sql指令碼:
 *  drop t_act if exists;
 *  create table t_act(
 *  actno int,
 *  balance double(7,2)
 *  );
 *  insert into t_act(actno,balance) values(5566,1000);
 *  insert into t_act(actno,balance) values(1314,0);
 */

public class JDBCTransactionTest01 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");

            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode"
                    , "root", "888");

            String sql = "update t_act set balance = ? where actno = ?";
            ps = connection.prepareStatement(sql);
            ps.setDouble(1, 0);
            ps.setDouble(2, 5566);

            count = ps.executeUpdate();

            String s = null;
            s.toString();

            String sql0 = "update t_act set balance = ? where actno = ?";
            ps = connection.prepareStatement(sql0);
            ps.setDouble(1, 1000);
            ps.setDouble(2, 1314);

            count += ps.executeUpdate();
            System.out.println("更新資料:" + count + "條");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(count == 2?"轉賬成功":"轉賬失敗");
        }
    }
}

IDEA控制檯輸出結果:

java.lang.NullPointerException
	at com.bjpowernode.jdbc.JDBCTransactionTest01.main(JDBCTransactionTest01.java:48)
轉賬失敗

Process finished with exit code 0

現在瞅一眼 t_act:

+-------+---------+
| actno | balance |
+-------+---------+
| 5566 | 0.00 |
| 1314 | 0.00 |
+-------+---------+

哎呀我去,這bug太嚴重了,錢都飛了!!


/*
1、功能:實現轉賬功能(修正版)

2、需求;使每次同一轉賬事務中,多條 DML語句 同時成功/同時失敗

3、t_act:(原表)
+-------+---------+
| actno | balance |
+-------+---------+
| 5566 | 1000.00 |
| 1314 | 0.00 |
+-------+---------+

*/

import java.sql.*;

public class JDBCTransactionTest02 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement ps = null;
        int count = 0;

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");

            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode"
                    , "root", "888");

            //將自動提交機制修改為手動提交
            connection.setAutoCommit(false);

            String sql = "update t_act set balance = ? where actno = ?";
            ps = connection.prepareStatement(sql);
            ps.setDouble(1, 0);
            ps.setDouble(2, 5566);

            count = ps.executeUpdate();

            String s = null;
            s.toString();

            String sql0 = "update t_act set balance = ? where actno = ?";
            ps = connection.prepareStatement(sql0);
            ps.setDouble(1, 1000);
            ps.setDouble(2, 1314);

            count += ps.executeUpdate();
            System.out.println("更新資料:" + count + "條");

            //程式執行到這說明沒有異常,事務結束,手動提交資料
            connection.commit();
        } catch (Exception e) {
            //如果出現異常,回滾事務
            if (connection != null) {
                try {
                    connection.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(count == 2?"轉賬成功":"轉賬失敗");
        }
    }
}

IDEA控制檯輸出結果:

java.lang.NullPointerException
	at com.bjpowernode.jdbc.JDBCTransactionTest02.main(JDBCTransactionTest02.java:31)
轉賬失敗

Process finished with exit code 0

現在瞅一眼 t_act:

+-------+---------+
| actno | balance |
+-------+---------+
| 5566 | 1000.00 |
| 1314 | 0.00 |
+-------+---------+

雖然因為某些原因導致轉賬失敗,但是資料庫中儲存的資料一切正常,而且控制檯也給出了提示(轉賬失敗),所以總結:此轉賬程式非常成功!