日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

事务及事务隔离级别

發布時間:2025/3/12 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 事务及事务隔离级别 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是事務

事務是訪問數據庫的一個操作序列,數據庫應用系統通過事務集來完成對數據庫的存取。事務的正確執行使得數據庫從一種狀態轉換為另一種狀態。

事務必須服從ISO/IEC所制定的ACID原則。ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)、持久性(durability)的縮寫,這四種狀態的意思是:

1、原子性

即不可分割,事務要么全部被執行,要么全部不執行。如果事務的所有子事務全部提交成功,則所有的數據庫操作被提交,數據庫狀態發生變化;如果有子事務失敗,則其他子事務的數據庫操作被回滾,即數據庫回到事務執行前的狀態,不會發生狀態轉換

2、一致性

事務的執行使得數據庫從一種正確狀態轉換成另外一種正確狀態

3、隔離性

在事務正確提交之前,不允許把事務對該數據的改變提供給任何其他事務,即在事務正確提交之前,它可能的結果不應該顯示給其他事務

4、持久性

事務正確提交之后,其結果將永遠保存在數據庫之中,即使在事務提交之后有了其他故障,事務的處理結果也會得到保存

事務的作用

事務管理對于企業級應用而言至關重要,它保證了用戶的每一次操作都是可靠的,即便出現了異常的訪問情況,也不至于破壞后臺數據的完整性。就像銀行的自動提款機ATM,通常ATM都可以正常為客戶服務,但是也難免遇到操作過程中及其突然出故障的情況,此時,事務就必須確保出故障前對賬戶的操作不生效,就像用戶剛才完全沒有使用過ATM機一樣,以保證用戶和銀行的利益都不受損失。

并發下事務會產生的問題

舉個例子,事務A和事務B操縱的是同一個資源,事務A有若干個子事務,事務B也有若干個子事務,事務A和事務B在高并發的情況下,會出現各種各樣的問題。“各種各樣的問題”,總結一下主要就是五種:第一類丟失更新、第二類丟失更新、臟讀、不可重復讀、幻讀。五種之中,第一類丟失更新、第二類丟失更新不重要,不講了,講一下臟讀、不可重復讀和幻讀。

1、臟讀

所謂臟讀,就是指事務A讀到了事務B還沒有提交的數據,比如銀行取錢,事務A開啟事務,此時切換到事務B,事務B開啟事務–>取走100元,此時切換回事務A,事務A讀取的肯定是數據庫里面的原始數據,因為事務B取走了100塊錢,并沒有提交,數據庫里面的賬務余額肯定還是原始余額,這就是臟讀。

2、不可重復讀

所謂不可重復讀,就是指在一個事務里面讀取了兩次某個數據,讀出來的數據不一致。還是以銀行取錢為例,事務A開啟事務–>查出銀行卡余額為1000元,此時切換到事務B事務B開啟事務–>事務B取走100元–>提交,數據庫里面余額變為900元,此時切換回事務A,事務A再查一次查出賬戶余額為900元,這樣對事務A而言,在同一個事務內兩次讀取賬戶余額數據不一致,這就是不可重復讀。

3、幻讀

所謂幻讀,就是指在一個事務里面的操作中發現了未被操作的數據。比如學生信息,事務A開啟事務–>修改所有學生當天簽到狀況為false,此時切換到事務B,事務B開啟事務–>事務B插入了一條學生數據,此時切換回事務A,事務A提交的時候發現了一條自己沒有修改過的數據,這就是幻讀,就好像發生了幻覺一樣。幻讀出現的前提是并發的事務中有事務發生了插入、刪除操作。

事務隔離級別

事務隔離級別,就是為了解決上面幾種問題而誕生的。為什么要有事務隔離級別,因為事務隔離級別越高,在并發下會產生的問題就越少,但同時付出的性能消耗也將越大,因此很多時候必須在并發性和性能之間做一個權衡。所以設立了幾種事務隔離級別,以便讓不同的項目可以根據自己項目的并發情況選擇合適的事務隔離級別,對于在事務隔離級別之外會產生的并發問題,在代碼中做補償。

事務隔離級別有4種,但是像Spring會提供給用戶5種,來看一下:

1、DEFAULT

默認隔離級別,每種數據庫支持的事務隔離級別不一樣,如果Spring配置事務時將isolation設置為這個值的話,那么將使用底層數據庫的默認事務隔離級別。順便說一句,如果使用的MySQL,可以使用"select @@tx_isolation"來查看默認的事務隔離級別

2、READ_UNCOMMITTED

讀未提交,即能夠讀取到沒有被提交的數據,所以很明顯這個級別的隔離機制無法解決臟讀、不可重復讀、幻讀中的任何一種,因此很少使用

3、READ_COMMITED

讀已提交,即能夠讀到那些已經提交的數據,自然能夠防止臟讀,但是無法限制不可重復讀和幻讀

4、REPEATABLE_READ

重復讀取,即在數據讀出來之后加鎖,類似"select * from XXX for update",明確數據讀取出來就是為了更新用的,所以要加一把鎖,防止別人修改它。REPEATABLE_READ的意思也類似,讀取了一條數據,這個事務不結束,別的事務就不可以改這條記錄,這樣就解決了臟讀、不可重復讀的問題,但是幻讀的問題還是無法解決

5、SERLALIZABLE

串行化,最高的事務隔離級別,不管多少事務,挨個運行完一個事務的所有子事務之后才可以執行另外一個事務里面的所有子事務,這樣就解決了臟讀、不可重復讀和幻讀的問題了

網上專門有圖用表格的形式列出了事務隔離級別解決的并發問題:

再必須強調一遍,不是事務隔離級別設置得越高越好,事務隔離級別設置得越高,意味著勢必要花手段去加鎖用以保證事務的正確性,那么效率就要降低,因此實際開發中往往要在效率和并發正確性之間做一個取舍,一般情況下會設置為READ_COMMITED,此時避免了臟讀,并發性也還不錯,之后再通過一些別的手段去解決不可重復讀和幻讀的問題就好了。

事物隔離級別查看及修改

首先說明一下MySQL查看和修改事務隔離級別的幾個命令:

  • 查看事務隔離級別使用select @@tx_isolation
  • 修改當前會話事務隔離級別使用SET session TRANSACTION ISOLATION LEVEL Serializable;(參數可以為:Read uncommitted|Read committed|Repeatable read|Serializable)
  • 修改全局事務隔離級別使用SET global TRANSACTION ISOLATION LEVEL Serializable;(參數可以為:Read uncommitted|Read committed|Repeatable read|Serializable)

修改了會話的事務隔離級別,比如MyBatis,getSqlSession()的時候,只針對這一次拿到的Session有效;比如CMD命令行,只對這一次的窗口有效。

修改了全局的事務隔離級別,那么針對此后所有的會話有效,當前已經存在的會話不受影響。

[Mysql]——通過例子理解事務的4種隔離級別

SQL標準定義了4種隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。

低級別的隔離級一般支持更高的并發處理,并擁有更低的系統開銷。

首先,我們使用 test 數據庫,新建 tx 表,并且如圖所示打開兩個窗口來操作同一個數據庫:

第1級別:Read Uncommitted(讀取未提交內容)

(1)所有事務都可以看到其他未提交事務的執行結果
(2)本隔離級別很少用于實際應用,因為它的性能也不比其他級別好多少
(3)該級別引發的問題是——臟讀(Dirty Read):讀取到了未提交的數據

#首先,修改隔離級別 set tx_isolation='READ-UNCOMMITTED'; select @@tx_isolation; +------------------+ | @@tx_isolation | +------------------+ | READ-UNCOMMITTED | +------------------+#事務A:啟動一個事務 start transaction; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +------+------+#事務B:也啟動一個事務(那么兩個事務交叉了)在事務B中執行更新語句,且不提交 start transaction; update tx set num=10 where id=1; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +------+------+#事務A:那么這時候事務A能看到這個更新了的數據嗎? select * from tx; +------+------+ | id | num | +------+------+ | 1 | 10 | --->可以看到!說明我們讀到了事務B還沒有提交的數據 | 2 | 2 | | 3 | 3 | +------+------+#事務B:事務B回滾,仍然未提交 rollback; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +------+------+#事務A:在事務A里面看到的也是B沒有提交的數據 select * from tx; +------+------+ | id | num | +------+------+ | 1 | 1 | --->臟讀意味著我在這個事務中(A),事務B雖然沒有提交,但它任何一條數據變化,我都可以看到! | 2 | 2 | | 3 | 3 | +------+------+

第2級別:Read Committed(讀取提交內容)

(1)這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)
(2)它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變
(3)這種隔離級別出現的問題是——不可重復讀(Nonrepeatable Read):不可重復讀意味著我們在同一個事務中執行完全相同的select語句時可能看到不一樣的結果。
|——>導致這種情況的原因可能有:(1)有一個交叉的事務有新的commit,導致了數據的改變;(2)一個數據庫被多個實例操作時,同一事務的其他實例在該實例處理其間可能會有新的commit

#首先修改隔離級別 set tx_isolation='read-committed'; select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | READ-COMMITTED | +----------------+#事務A:啟動一個事務 start transaction; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +------+------+#事務B:也啟動一個事務(那么兩個事務交叉了)在這事務中更新數據,且未提交 start transaction; update tx set num=10 where id=1; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +------+------+#事務A:這個時候我們在事務A中能看到數據的變化嗎? select * from tx; ---------------> +------+------+ | | id | num | | +------+------+ | | 1 | 1 |--->并不能看到! | | 2 | 2 | | | 3 | 3 | | +------+------+ |——>相同的select語句,結果卻不一樣| #事務B:如果提交了事務B? | commit; || #事務A: | select * from tx; ---------------> +------+------+ | id | num | +------+------+ | 1 | 10 |--->因為事務B已經提交了,所以在A中我們看到了數據變化 | 2 | 2 | | 3 | 3 | +------+------+

第3級別:Repeatable Read(可重讀)

(1)這是MySQL的默認事務隔離級別
(2)它確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行
(3)此級別可能出現的問題——幻讀(Phantom Read):當用戶讀取某一范圍的數據行時,另一個事務又在該范圍內插入了新行,當用戶再讀取該范圍的數據行時,會發現有新的“幻影” 行
(4)InnoDB和Falcon存儲引擎通過多版本并發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題

#首先,更改隔離級別 set tx_isolation='repeatable-read'; select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+#事務A:啟動一個事務 start transaction; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +------+------+#事務B:開啟一個新事務(那么這兩個事務交叉了)在事務B中更新數據,并提交 start transaction; update tx set num=10 where id=1; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +------+------+ commit;#事務A:這時候即使事務B已經提交了,A能不能看到數據變化? select * from tx; +------+------+ | id | num | +------+------+ | 1 | 1 | --->還是看不到的!(這個級別2不一樣,也說明級別3解決了不可重復讀問題) | 2 | 2 | | 3 | 3 | +------+------+#事務A:只有當事務A也提交了,它才能夠看到數據變化 commit; select * from tx; +------+------+ | id | num | +------+------+ | 1 | 10 | | 2 | 2 | | 3 | 3 | +------+------+

第4級別:Serializable(可串行化)

(1)這是最高的隔離級別
(2)它通過強制事務排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,它是在每個讀的數據行上加上共享鎖。
(3)在這個級別,可能導致大量的超時現象和鎖競爭

#首先修改隔離界別 set tx_isolation='serializable'; select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | SERIALIZABLE | +----------------+#事務A:開啟一個新事務 start transaction;#事務B:在A沒有commit之前,這個交叉事務是不能更改數據的 start transaction; insert tx values('4','4'); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction update tx set num=10 where id=1; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

總結

以上是生活随笔為你收集整理的事务及事务隔离级别的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。