JDBC事務自動提交機制
首先我們先來看一段代碼:
package com.guisha.JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/**
* 方法描述
* @since: 1.0.0
* @param:
* @return:
* @author: Mr.cheng
* @date: 2021年1月6日 21點48分
*/
public class JDBCTest_03 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
InputStream input = JDBCTest_03.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//配置文件取值復制給新變量
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注冊驅動
Class.forName(driver);
try {
//獲取鏈接
conn = DriverManager.getConnection(url, user, password);
String sql = "UPDATE LOGINNAME SET NAMEPASS = ? WHERE NAME = ? ";
//獲取數據庫操作對象
ps = conn.prepareStatement(sql);
//添加sql數據
ps.setString(1,"guisha");
ps.setString(2,"Mrcheng");
//執行SQL語句,返回條數
int i = ps.executeUpdate();
System.out.println(i);
ps = conn.prepareStatement(sql);
ps.setString(1,"wuxin");
ps.setString(2,"wuxin");
int i1 = ps.executeUpdate();
System.out.println(i1);
} catch (SQLException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
//關閉資源
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
代碼中,我們更新2條數據,但是在 int i = ps.executeUpdate(); 這里會自動提交事務,可以理解為提交SQL語句對數據庫修改
我們需要了解JDBC的事務是自動提交的,什么是自動提交?
1)只執行任意一條DML語句,則提交一次。JDBC默認的提交方式是自動提交,是JDBC默認的事務行為
2)在實際開發業務中,通常都是N條DML語句共同聯合才能完成的,必須保證DML語句在一個事務中同時成功或者同時失敗
我們來看一個小例子來驗證以下JDBC的事務是否是自動提交機制!
兩個人轉賬的小案例:
package com.guisha.JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/**
* 方法描述
* @since: 1.0.0
* @param:
* @return:
* @author: Mr.cheng
* @date: 2021年1月6日 21點48分
*/
public class JDBCTest_04 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
InputStream input = JDBCTest_04.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//配置文件取值復制給新變量
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注冊驅動
Class.forName(driver);
try {
//獲取鏈接
conn = DriverManager.getConnection(url, user, password);
String sql = "UPDATE center_cat SET user_baln = ? WHERE USER_NAME = ? ";
//獲取數據庫操作對象
ps = conn.prepareStatement(sql);
//添加sql數據
ps.setDouble(1,10000);
ps.setString(2,"小明");
//執行SQL語句,返回條數
int i = ps.executeUpdate();
System.out.println(i);
//自定義NullPointerException
String s = null;
s.toString();
ps.setString(1,"10000");
ps.setString(2,"王老頭");
i += ps.executeUpdate();
System.out.println(i);
} catch (SQLException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
//關閉資源
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
運行之后會出錯,我們程序中定義的 NullPointerException

再查看數據庫,數據庫執行一半出現異常終止,小明資金共20000,現在能夠看出來 小明明學轉出的10000元消失不見了,這里就是每執行一條DML語句,事務會自動提交一次

現在我們設置是為手動開啟和手動提交,如果中間出現錯誤,我們回滾數據
代碼如下:
package com.guisha.JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/**
* 方法描述
* @since: 1.0.0
* @param:
* @return:
* @author: Mr.cheng
* @date: 2021年1月6日 21點48分
*/
public class JDBCTest_04 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
InputStream input = JDBCTest_04.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//配置文件取值復制給新變量
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注冊驅動
Class.forName(driver);
try {
//獲取鏈接
conn = DriverManager.getConnection(url, user, password);
//開啟事務
conn.setAutoCommit(false);
String sql = "UPDATE center_cat SET user_baln = ? WHERE USER_NAME = ? ";
//獲取數據庫操作對象
ps = conn.prepareStatement(sql);
//第一次給?傳值
ps.setDouble(1,10000);
ps.setString(2,"小明");
//執行SQL語句,返回條數
int i = ps.executeUpdate();
System.out.println(i);
// 自定義NullPointerException 用來終止正在執行的程序,用於演示JDBC事務自動提交機制的問題
// 想正常實執行代碼,請刪除自定義自定義NullPointerException異常
String s = null;
s.toString();
//第二次給?傳值
ps.setString(1,"10000");
ps.setString(2,"王老頭");
i += ps.executeUpdate();
System.out.println(i == 2 ? "轉賬成功!": "轉賬失敗!");
//提交事務
conn.commit();
} catch (SQLException e) {
/ //數據回滾
if (conn !=null){
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
//關閉資源
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
以上代碼就算出錯,數據會進行回滾,重點使用了conn.setAutoCommit(false)(手動開啟事務)、conn.commit()(手動提交事務)和conn.rollback(手動回滾數據)
正常執行如下:
package com.guisha.JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
/**
* 方法描述
* @since: 1.0.0
* @param:
* @return:
* @author: Mr.cheng
* @date: 2021年1月6日 21點48分
*/
public class JDBCTest_04 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
InputStream input = JDBCTest_04.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//配置文件取值復制給新變量
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注冊驅動
Class.forName(driver);
try {
//獲取鏈接
conn = DriverManager.getConnection(url, user, password);
//開啟事務
conn.setAutoCommit(false);
String sql = "UPDATE center_cat SET user_baln = ? WHERE USER_NAME = ? ";
//獲取數據庫操作對象
ps = conn.prepareStatement(sql);
//第一次給?傳值
ps.setDouble(1,10000);
ps.setString(2,"小明");
//執行SQL語句,返回條數
int i = ps.executeUpdate();
System.out.println(i);
//第二次給?傳值
ps.setString(1,"10000");
ps.setString(2,"王老頭");
i += ps.executeUpdate();
System.out.println(i == 2 ? "轉賬成功!": "轉賬失敗!");
//提交事務
conn.commit();
} catch (SQLException e) {
if (conn !=null){
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
//關閉資源
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
