資料庫事務
- 事務: 一組邏輯操作單元,使資料從一種狀态變換到另一種狀态。
-
事務處理(事務操作): 保證所有事務都作為一個工作單元來執行,即 使出現了故障,都不能改變這種執行方式。當在一個事務中執行多個操 作時,要麼所有的事務都被送出(commit),那麼這些修改就永久地儲存 下來;要麼資料庫管理系統将放棄所作的所有修改,整個事務復原
(rollback)到最初狀态。
-
為確定資料庫中資料的一緻性,資料的操縱應當是離散的成組的邏輯單元:
當它全部完成時,資料的一緻性可以保持,而當這個單元中的一部分操作
失敗,整個事務應全部視為錯誤,所有從起始點以後的操作應全部回退到
開始狀态。
JDBC 事務處理
-
當一個連接配接對象被建立時,預設情況下是自動送出事務:每次執行一個
SQL 語句時,如果執行成功,就會向資料庫自動送出,而不能復原
-
為了讓多個 SQL 語句作為一個事務執行:
1.調用 Connection 對象的 setAutoCommit(false); 以取消自動送出事務
2.在所有的 SQL 語句都成功執行後,調用 commit(); 方法送出事務
3.在出現異常時,調用 rollback(); 方法復原事務
4.若此時 Connection 沒有被關閉, 則需要恢複其自動送出狀态
- 資料庫事務使用的過程
public void testJDBCTransaction() {
Connection conn = null;
try {
// 1.擷取資料庫連接配接
conn = JDBCUtils.getConnection();
// 2.開啟事務
conn.setAutoCommit(false);
// 3.進行資料庫操作
// 4.若沒有異常,則送出事務
conn.commit();
} catch (Exception e) {
e.printStackTrace();
// 5.若有異常,則復原事務
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
JDBCUtils.close(null, null, conn);
}
}
考慮資料庫事務前後的操作執行個體
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.swing.table.TableColumn;
import com.atguigu1.util.JDBCUtils;
public class Transaction {
public static void main(String[] args) {
Transaction transaction = new Transaction();
transaction.testUpdateWithTx();
}
// ***************為考慮資料庫事務情況下的轉賬操作***************************
// 通用的增删改操作
// sql中占位符的個數與可變形參的長度相同
public void update(String sql, Object... args) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 1.擷取資料庫的連接配接
conn = JDBCUtils.getConnection();
// 2.預編譯sql語句,傳回PreparedStatement的執行個體
ps = conn.prepareStatement(sql);
// 3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]); // 小心參數聲明錯誤
}
// 4.執行
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 修改其為自動送出資料
// 主要針對于使用資料庫連接配接池的使用
try {
conn.setAutoCommit(true);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 5.資源的關閉
JDBCUtils.closeResource(conn, ps);
}
}
public void testUpdateWithTx() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
System.out.println(conn.getAutoCommit());
// 1.取消自動送出
conn.setAutoCommit(false);
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update(conn, sql1, "AA");
// 模拟網絡異常
// System.out.println(10 / 0);
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update(conn, sql2, "BB");
System.out.println("轉賬成功");
// 2.送出資料
conn.commit();
} catch (Exception e) {
e.printStackTrace();
// 復原資料
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} finally {
JDBCUtils.closeResource(conn, null);
}
}
// *******************考慮資料庫事務後的轉賬操作*************************************
// 通用的增删改查操作---version2.0(考慮上事務)
public int update(Connection conn, String sql, Object... args) {
PreparedStatement ps = null;
try {
// 1.預編譯sql語句,傳回PreparedStatement的執行個體
ps = conn.prepareStatement(sql);
// 2.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]); // 小心參數聲明錯誤
}
// 3.執行
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 5.資源的關閉
JDBCUtils.closeResource(null, ps);
}
return 0;
}
}
事務 的ACID屬性
-
原子性(Atomicity)
原子性是指事務是一個不可分割的工作機關,事務中的操作要麼都發生,要麼都不
發生。
-
一緻性 (Consistency)
事務必須使資料庫從一個一緻性狀态變換到另外一個一緻性狀态。
-
隔離性(Durability)
事務的隔離性是指一個事務的執行不能被其他事務幹擾,即一個事務内部的操作及
使用的資料對并發的其他事務是隔離的,并發執行的各個事務之間不能互相幹擾。
-
持久性(Durability)
持久性是指一個事務一旦被送出,它對資料庫中資料的改變就是永久性的,接下來
的其他操作和資料庫故障不應該對其有任何影響
資料庫的隔離級别
- 對于同時運作的多個事務, 當這些事務通路資料庫中相同的資料時, 如果沒有采取必要的 隔離機制, 就會導緻各種并發問題:
髒讀: 對于兩個事務 T1, T2, T1 讀取了已經被 T2 更新但還沒有被送出的字段。之後, 若 T2 回
滾, T1讀取的内容就是臨時且無效的。
不可重複讀: 對于兩個事務T1, T2, T1 讀取了一個字段, 然後 T2 更新了該字段。之後, T1再次
讀取同一個字段, 值就不同了。
幻讀: 對于兩個事務T1, T2, T1 從一個表中讀取了一個字段, 然後 T2 在該表中插入了一些新的
行。之後, 如果 T1 再次讀取同一個表, 就會多出幾行。
- 資料庫事務的隔離性: 資料庫系統必須具有隔離并發運作各個事務的能力, 使它們不會相 互影響, 避免各種并發問題。
-
一個事務與其他事務隔離的程度稱為隔離級别. 資料庫規定了多種事務隔離級别, 不同隔
離級别對應不同的幹擾程度, 隔離級别越高, 資料一緻性就越好, 但并發性越弱。
- 資料庫提供的 4 種事務隔離級别:
- Oracle 支援的 2 種事務隔離級别:READ COMMITED, SERIALIZABLE。Oracle 預設的事務隔離級别為: READ COMMITED
-
Mysql 支援 4 種事務隔離級别. Mysql 預設的事務隔離級别為:
REPEATABLE READ
在MySql 中設定隔離級别
- 每啟動一個 mysql 程式, 就會獲得一個單獨的資料庫連接配接. 每個資料庫連接配接都有一個全局變量 @@tx_isolation, 表示目前的事務隔離級别
- 檢視目前的隔離級别: SELECT @@tx_isolation;
-
設定目前 mySQL 連接配接的隔離級别:
set transaction isolation level read committed;
-
設定資料庫系統的全局的隔離級别:
set global transaction isolation level read committed;
- SET autocommit = 0; 禁止操作自動送出