【JDBC】筆記(4)--- JDBC 事務自動提交機制;賬戶轉賬演示事務程式碼(bug版+修正版)
楔子:
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 |
+-------+---------+
雖然因為某些原因導致轉賬失敗,但是資料庫中儲存的資料一切正常,而且控制檯也給出了提示(轉賬失敗),所以總結:此轉賬程式非常成功!