在編寫業務的過程中,會需要進行事務處理,當需要執行多條插入語句時,如果前幾條成功,而最後一條失敗,那麼我們需要回滾數據庫操作,保持數據的一致性和完整性,此時,就需要利用DB的事務處理。事務是恢復和併發控制的基本單位。
簡單來說,所謂的事務,是一個操作序列,這些操作要麼都執行,要麼都不執行,它是一個不可分割的工作單位。
事務應該具有4個屬性:原子性、一致性、隔離性、持久性。這四個屬性通常稱爲ACID特性。
1.示例
package tran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
//實現的業務是:1給2轉10塊錢
public class Account {
private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql連接驅動,無需改
private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
private static String jdbcuser = "root"; // 數據庫用戶名
private static String jdbcpwd = "root"; // 數據庫密碼
private static Connection conn;
public static PreparedStatement ps;
public static void main(String[] args) {
try {
Class.forName(jdbcDriver);
conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驅動利用驅動地址,數據庫用戶名,密碼創建連接
ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=person1;");
ps.executeUpdate();
ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=person2;");
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關閉資源
}
}
}
package tran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class Account {
private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql連接驅動,無需改
private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
private static String jdbcuser = "root"; // 數據庫用戶名
private static String jdbcpwd = "root"; // 數據庫密碼
private static Connection conn;
public static PreparedStatement ps;
public static void main(String[] args) {
try {
Class.forName(jdbcDriver);
conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驅動利用驅動地址,數據庫用戶名,密碼創建連接
ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=person1;");
ps.executeUpdate();
int i=1/0;//這裏設置一個錯誤。
ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=person2;");
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關閉資源
}
}
}
4.解決方案-事務
package tran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Account {
private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql連接驅動,無需改
private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
private static String jdbcuser = "root"; // 數據庫用戶名
private static String jdbcpwd = "root"; // 數據庫密碼
private static Connection conn;
public static PreparedStatement ps;
public static void main(String[] args) {
try {
Class.forName(jdbcDriver);
conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驅動利用驅動地址,數據庫用戶名,密碼創建連接
conn.setAutoCommit(false);// 設置不自動提交
ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=person1;");
ps.executeUpdate();
int i = 1 / 0;
ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=person2;");
ps.executeUpdate();
conn.commit();// 如果上面的執行都沒問題,再提交。
} catch (Exception e) {
try {
conn.rollback(); //如果出錯則 執行回滾
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
// 關閉資源
}
}
}
回滾的作用就是,當有一個SQL語句執行時,條件不符合要求,比如你要插入一個數據,但是插入的數據要有條件的,這時候你就可以用回滾,如果條件成功就COMMIT提交的意思,不然就ROLLBACK回滾,也就是說插入不成功
package tran;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;
public class Account {
private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql連接驅動,無需改
private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
private static String jdbcuser = "root"; // 數據庫用戶名
private static String jdbcpwd = "root"; // 數據庫密碼
private static Connection conn;
public static PreparedStatement ps;
static Savepoint sp;
public static void main(String[] args) {
try {
Class.forName(jdbcDriver);
conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驅動利用驅動地址,數據庫用戶名,密碼創建連接
conn.setAutoCommit(false);// 設置不自動提交
ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=person1;");
ps.executeUpdate();
ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=person2;");
ps.executeUpdate();
sp = conn.setSavepoint();//設置一個保存點
// 發送短信業務
// 模擬業務出錯
int i = 1 / 0;//因爲不是重要業務部分,所以出錯後回滾到保存點提交數據到數據庫
conn.commit();// 如果上面的執行都沒問題,再提交。
} catch (Exception e) {
if(sp!=null){//只簡單說明,實際還要判斷conn是不是null
try {
conn.rollback(sp);//回滾到內個設置點
conn.commit();//提交保存點之前的數據到數據庫
} catch (SQLException e1) {
e1.printStackTrace();
}elseif(sp==null){ conn.rollback();//若果保存點之前出錯出錯 則回滾全部
}
}
e.printStackTrace();
} finally {
// 關閉資源
}
}
}