事務:一組對數據庫的讀寫操作,必須具有以下四種特性的操作才能叫做事務。
ACID:原子性、一致性、隔離性、持久性。
原子性:這組操作要么全部成功完成,要么就回滾到執行前的狀態。
一致性:事務執行前和執行后系統的總數據是一致的,eg:銀行無論怎么同行間轉賬,錢的總數是不變的。
隔離性:事務之間是不可見的,一個事務是感知不到其他事務的存在,就像是事務間串行化執行一樣,保證了事務執行過程中短暫的不一致性對其他事務不可見。
持久性:事務完成后,事務所做出的改變會存儲到數據庫中,不會被回滾。
不考慮隔離會產生的問題:丟失更新、臟讀、不可重復讀(虛讀、幻讀)
丟失更新:當一個事務對一個數據進行修改,因為修改的操作不是原子的,再修改的過程中,另一個事務也對該數據進行修改,而如果第二個事務的修改先完成,那么第一個事務進行的修改就會把第二個事務的修改覆蓋。
臟讀:當一個事務執行過程中修改了某個數據,這時,另一個事務讀到這個數據叫做臟讀,因為如果第一個事務進行回滾的話,那么數據本身沒有改變,其他事務讀到的是錯誤的數據。
虛讀:當事務讀取某個數據后,另一個數據對該數據進行了修改,而第一個事務再次讀取該數據就會發現兩次讀取結果不一致。
幻讀:一個事務讀取幾行數據后,另一個事務插入了幾行數據,則第一個事務再次讀取時就會發現多了幾行數據,和虛讀的區別在於,虛讀是針對一個數據的重復讀不一致問題,幻讀是對一組數據重復讀的不一致。虛讀的重點是修改,幻讀的重點在於新增或者刪除。
想要真正理解四種隔離級別需要了解下數據庫的鎖的種類
共享鎖:某個事務對數據加上共享鎖以后,只能讀取該數據,其他事務不能加排他鎖,只可以加共享鎖,或者直接讀。
排他鎖:加了以后只能允許該事務進行讀取或者修改,其他事務不能上鎖,只能不加鎖的讀,或者等釋放了鎖以后再加鎖。
在數據庫增刪改查四種操作中,insert、delete和update都是會加排它鎖(Exclusive Locks)的,而select只有顯式聲明才會加鎖:
- select: 即最常用的查詢,是不加任何鎖的
- select ... lock in share mode: 會加共享鎖(Shared Locks)
- select ... for update: 會加排它鎖
四種隔離級別:都不會產生丟失更新的問題,因為產生丟失更新是事務同時對數據進行寫操作,而所有的隔離級別都要求寫操作必須加排他鎖。
讀取未提交(read-uncommitted):寫加排他鎖,讀允許不加鎖。所以最壞的情況就是,一個事務讀取到另一個事務修改后但是沒有提交的數據。會造成臟讀、幻讀、虛讀。
讀已提交(read-committed):如果讀的時候數據被加排他鎖,那就讀取該數據的歷史版本(MVCC),每次讀取都是歷史版本,這樣就避免了臟讀。
可重讀(REPEATABLE READ):和讀已提交類似只是,只有在第一次讀的時候是使用MVCC查詢歷史版本,再繼續讀都是都是讀到的這個版本。這樣避免了虛讀。
串行化(SERIALISABLE):讀會加共享鎖,寫加排他鎖。避免了所有壞的情況,但是並發度大大下降。
mysql默認的隔離級別是可重讀。