楔子:
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 |
+-------+---------+
雖然因為某些原因導致轉賬失敗,但是資料庫中儲存的資料一切正常,而且控制臺也給出了提示(轉賬失敗),所以總結:此轉賬程式非常成功!
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/401438.html
標籤:MySQL
