1、事務
事務是訪問數據庫的一個操作序列,數據庫應用系統(tǒng)通過事務集來完成對數據庫的存取。事務的正確執(zhí)行使得數據庫從一種狀態(tài)轉換成另一種狀態(tài)。
當操作序列中的所有操作都成功執(zhí)行時,事務的狀態(tài)未成功。當任一操作失敗時,事務的狀態(tài)為失敗,此時必須將程序狀態(tài)返回至事務未執(zhí)行時的狀態(tài),即回滾。
1.2 四個特性
原子性(Atomicity):事務中的所有操作是不可再分割的原子單位,事務中的所有操作是一個整體,或者整體執(zhí)行成功,亦或者整體執(zhí)行失敗。
一致性(Consistency):事務執(zhí)行后,數據庫狀態(tài)與其他業(yè)務規(guī)則保持一致。如轉賬業(yè)務,無論執(zhí)行成功與否,參與轉賬的兩個帳號余額值和應該是不變的。
隔離性(Isolation):在并發(fā)操作中,不同事務之間應該隔離開來,每個并發(fā)中的事務的執(zhí)行不會相互干擾。
持久性(Durability):一旦事務提交成功,事務中的所有數據更新必須被持久化到數據庫中,即使提交事務后,數據庫馬上崩潰,在數據庫重新啟動時,也必須能保證通過某種機制恢復數據。
1.3 數據庫的兩種事務模式
(1)自動提交模式:每個SQL語句都是一個獨立的事務,當數據庫系統(tǒng)執(zhí)行完一個SQL語句后,會自動提交事務。
(2)手動提交模式:必須由數據庫客戶程序顯示指定事務開始邊界和結束邊界。
默認是自動提交模式
1.4 數據庫讀寫中的并發(fā)事務問題
(1)臟讀(Dirty Read):在事務的執(zhí)行過程中,讀取到了其他事務的 未提交 的數據,即讀到了臟數據。
(2)不可重復讀(Unrepeatable Read):在事務的執(zhí)行過程中,讀到了其他事務 修改后 的數據,換句話說在該事務中的不同時間點讀取到了不一致的數據,即不可重復讀。
(3)幻讀/虛讀(Phantom Read):在事務的執(zhí)行過程中,讀取到了其他事務對 記錄數 修改后的數據,對同一張表的兩次查詢的 COUNT(*) 不一致。
不可重復讀與幻讀的區(qū)別:
不可重復讀:強調的是數據 內容 的不一致,主要針對 UPDATE 的修改。
幻讀:強調的是 記錄數 的不一致,主要針對 INSERT/DELETE 的修改。
1.5 四個隔離級別
并發(fā)事務問題的產生原因是,未能遵守事務的隔離特性
(1)串行化(SERIALIZABLE):所有的事務依次逐個執(zhí)行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。
(2)可重復讀(REPEATABLE_READ):該隔離級別表示一個事務在整個過程中可以多次重復執(zhí)行某個查詢,并且每次返回的記錄都相同。即使在多次查詢之間有新增的數據滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止臟讀和不可重復讀。
(3)讀已提交(READ_COMMITTED):該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。該級別可以防止臟讀,這也是大多數情況下的推薦值。
(4)讀未提交(READ_UNCOMMITTED):該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據。該級別不能防止臟讀和不可重復讀,因此很少使用該隔離級別。
不同隔離級別可避免的并發(fā)問題
| 隔離級別 | 臟讀 | 不可重復讀 | 幻讀 |
|---|---|---|---|
| 串行化 | Y | Y | Y |
| 可重復讀 | Y | Y | |
| 讀已提交 | Y | ||
| 讀未提交 |
2、應用
當一個事務未完成之前,寫操作不會真正寫入數據庫。同時需要注意,一個事務是以提交(commit)或者回滾(rollback)結束,否則會發(fā)生死鎖,導致表被鎖死,之后的任何正確操作都不會成功。
2.1 MySQL事務的應用
查看隔離級別語句:SELECT @@TX_ISOLATION;啟用事務:START TRANSACTION;設置隔離級別:set [global/session] transaction isolation level;提交:COMMIT;回滾:ROLLBACK;
# 開啟事務START TRANSACTION; # 執(zhí)行事務 SQL 語句 # SQL1 UPDATE Test_TableSET name = hhhWHERE id = 1; # SQL2 UPDATE Test_TableSET name = xxxWHERE id = 2; # 提交事務 COMMIT;
2.2 JDBC事務的應用
//設置隔離級別conn.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED); //啟用事務conn.setAutoCommit(false); //提交conn.commit(); //回滾conn.rollback();
try{ conn = jdbcTest.getConnection(sHostName, sPortNumber, sSid, userName, password);
conn.setTransactionIsolation(TRANSACTION_REPEATABLE_READ);
conn.setAutoCommit(false);
String SQL = "insert into Test_Table values('name1','age1')";
jdbcTest.excute(conn, SQL);
SQL = "insert into Test_Table values('name2','age2')";
jdbcTest.excute(conn, SQL);
conn.commit();}
catch (SQLException e){
if (conn != null) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();}
finally{ if (conn != null)
{
try
{
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}}
原文作者:萌太隆
原文地址:https://blog.csdn.net/swl979623074/article/details/79416470