最近在讀 《mysql 技術內幕 innodb 儲存引擎》,裡面提到的各種概念都很新鮮,以前聽說過髒讀、幻讀、不可重複讀,但是對於概念不甚了解,於是查了一下,這裡做個筆記。
資料庫事務特徵,即 acid:
a atomicity 原子性事務是乙個原子性質的操作單元,事務裡面的對資料庫的操作要麼都執行,要麼都不執行,
c consistent 一致性在事務開始之前和完成之後,資料都必須保持一致狀態,必須保證資料庫的完整性。也就是說,資料必須符合資料庫的規則。
i isolation 隔離性資料庫允許多個併發事務同事對資料進行操作,隔離性保證各個事務相互獨立,事務處理時的中間狀態對其它事務是不可見的,以此防止出現資料不一致狀態。可通過事務隔離級別設定:包括讀未提交(read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和序列化(serializable)
d durable 永續性乙個事務處理結束後,其對資料庫的修改就是永久性的,即使系統故障也不會丟失。
首先 mysql 裡有四個隔離級別:read uncommttied(可以讀取未提交資料)、read committed(可以讀取已提交資料)、repeatable read(可重複讀)、serializable(可序列化)。
在 innodb 中,預設為 repeatable 級別,innodb 中使用一種被稱為 next-key locking 的策略來避免幻讀(phantom)現象的產生。
使用select @@tx_isolation;
可以檢視 mysql 預設的事務隔離級別。
不同的事務隔離級別會導致不同的問題:
髒讀所謂髒讀是指乙個事務中訪問到了另外乙個事務未提交的資料,如下圖:
如果會話 2 更新 age 為 10,但是在 commit 之前,會話 1 希望得到 age,那麼會獲得的值就是更新前的值。或者如果會話 2 更新了值但是執行了 rollback,而會話 1 拿到的仍是 10。這就是髒讀。
幻讀乙個事務讀取2次,得到的記錄條數不一致:
上圖很明顯的表示了這個情況,由於在會話 1 之間插入了乙個新的值,所以得到的兩次資料就不一樣了。
不可重複讀
乙個事務讀取同一條記錄2次,得到的結果不一致:
由於在讀取中間變更了資料,所以會話 1 事務查詢期間的得到的結果就不一樣了。
解決方案也就是上文提到的四種隔離級別,他們可以最大程度避免以上三種情況的發生:
未授權讀取也稱為讀未提交(read uncommitted):允許髒讀取,但不允許更新丟失。如果乙個事務已經開始寫資料,則另外乙個事務則不允許同時進行寫操作,但允許其他事務讀此行資料。該隔離級別可以通過「排他寫鎖」實現。
授權讀取也稱為讀提交(read committed):允許不可重複讀取,但不允許髒讀取。這可以通過「瞬間共享讀鎖」和「排他寫鎖」實現。讀取資料的事務允許其他事務繼續訪問該行資料,但是未提交的寫事務將會禁止其他事務訪問該行。
可重複讀取(repeatable read)可重複讀取(repeatable read):禁止不可重複讀取和髒讀取,但是有時可能出現幻讀資料。這可以通過「共享讀鎖」和「排他寫鎖」實現。讀取資料的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務。
序列化(serializable)序列化(serializable):提供嚴格的事務隔離。它要求事務序列化執行,事務只能乙個接著乙個地執行,不能併發執行。僅僅通過「行級鎖」是無法實現事務序列化的,必須通過其他機制保證新插入的資料不會被剛執行查詢操作的事務訪問到。
隔離級別越高,越能保證資料的完整性和一致性,但是對併發效能的影響也越大。對於多數應用程式,可以優先考慮把資料庫系統的隔離級別設為read committed。它能夠避免髒讀取,而且具有較好的併發效能。儘管它會導致不可重複讀、幻讀和第二類丟失更新這些併發問題,在可能出現這類問題的個別場合,可以由應用程式採用悲觀鎖或樂觀鎖來控制。
髒讀,不可重複讀,幻讀
髒讀,不可重複讀,幻讀是由於資料庫事務的隔離性導致的問題。髒讀 乙個事務讀取到了其它未提交事務操作的記錄。不可重複讀 乙個事務a內,首次查詢到一條相同記錄,然後事務b修改該條記錄並提交,事務a再次執行相同查詢,得到了事務b更新後的結果,事務a兩次相同的查詢,卻得到了不同的結果,這個叫做不可重複讀。是...
髒讀 不可重複讀 幻讀
髒讀 事務a使用了資料,但是還沒來得及提交,事務b就使用了這個資料,對於事務b來說就是髒讀。允許髒讀 sql server select from category with nolock 不可重複讀 事務a在9點和12點都會操作乙份資料,但是在10點的時候,事務b也操作了該份資料,並且使其數值進行...
髒讀 不可重複讀 幻讀
總結 對於不可重複讀和幻讀的區別是 不可重複讀圈了一塊地,這塊地不允許任何人動用,但是不管旁邊的地方是否開闢了一塊地。幻讀是不僅是圈的地,而且附近也不允許有新的地。這個對於區間查詢會有影響。所以不可重複讀和幻讀最大的區別是區間查詢的結果會不會一樣。幻讀保證結果一樣,但是不可重複讀不保證。mysql的...