【sql DB】淺談髒讀
【前言】
小編在做基礎系統維護的時候,接觸到了修改伺服器上的sql server資料庫裡面的資料,之前的時候小編也學過sql的東西,不過現在全忘了(增刪改查,這些基本的還是會的),在刪除某一條資料的時候出現了這樣一個問題,要刪除這一條資料但是就是刪除不了,而且在刪除記錄裡面還有我之前操作過的刪除記錄,這就很奇怪了。於是乎,多方求助終於解決了,下面給大家簡單的介紹一下
【問題】
由於班級程式碼寫錯了,所以不得不刪除這條資料(如下圖),於是在刪除的時候就出現了問題,怎麼刪也刪不掉這條資料
但是徹底刪除裡面卻有刪除的記錄(如下圖),試了很多遍還是不行
【原因及解決方法】
這其實是DB的髒讀引起的,那麼何為髒讀?
所謂髒讀,就是指當一個事務正在訪問資料並且對資料進行了修改,而這種修改還沒有提交到資料庫中,這時,另外一個事務也訪問這個資料,然後使用了這個資料。因為這個資料是還沒有提交的資料,那麼另外一個事務讀到的這個資料是髒資料,依據髒資料所做的操作可能是不正確的
髒讀:一個事務讀取到了另外一個事務沒有提交的資料
事務1:更新一條資料
---------->事務2:讀取事務1更新的記錄
事務1:呼叫commit進行提交
此時事務2讀到的資料是儲存在資料庫記憶體中的資料,稱為髒讀。讀到的資料為髒資料
例如:
張三的工資為5000,事務A中把他的工資改為8000,但事務A尚未提交。
與此同時,
事務B正在讀取張三的工資,讀取到張三的工資為8000。
隨後,
事務A發生異常,而回滾了事務。張三的工資又回滾為5000。
最後,
事務B讀取到的張三工資為8000的資料即為髒資料,事務B做了一次髒讀
產生資料不一致的主要原因是併發操作破壞了事務的隔離性。併發控制就是要用正確的方式排程併發操作,使一個使用者事物的執行不受其它事務的干擾,從而避免造成資料的不一致性
鎖就是防止其他事務訪問指定的資源的手段,鎖是實現併發控制的主要方法,是多個使用者能夠同時操縱同一個資料庫中的資料而不發生不一致現象的重要保障。
處理以上隔離級別的問題,採用如下方法:
事務隔離五種級別:
TRANSACTION_NONE 不使用事務。
TRANSACTION_READ_UNCOMMITTED 允許髒讀。
TRANSACTION_READ_COMMITTED 防止髒讀,最常用的隔離級別,並且是大多數資料庫的預設隔離級別
TRANSACTION_REPEATABLE_READ 可以防止髒讀和不可重複讀,
TRANSACTION_SERIALIZABLE 可以防止髒讀,不可重複讀取和幻讀,(事務序列化)會降低資料庫的效率
以上的五個事務隔離級別都是在Connection介面中定義的靜態常量,使用setTransactionIsolation(int level) 方法可以設定事務隔離級別。如:con.setTransactionlsolation(Connection.REPEATABLE_READ);
注意:事務的隔離級別收到資料庫的限制,不同的資料庫支援的隔離級別不一定相同
髒讀:修改時加排他鎖,直到事務提交後才釋放,讀取時加上共享鎖後(這樣在事務1讀取資料的過程中,其他事務就不會修改該資料),不允許任何事務操作該資料,只能讀取,之後1如果有更新操作,那麼會轉換為排他鎖,其他事務更無權參與進來讀寫,這樣就防止了髒讀問題
但是當事務1讀取資料過程中,有可能其他事務也讀取了該資料,讀取完畢後共享鎖釋放,此時事務1修改資料,修改完畢提交事務,其他事務再次讀取資料時候發現數據不一致,就會出現先不可重複讀問題,所以這樣不能夠避免不可重複讀問題
當執行不同的隔離級別時,可能會發生各種各樣不同的問題。下面對他們進行總結並舉例說明:
髒讀發生在一個事務A讀取了被另一個事務B修改,但是還未提交的資料。假如B回退,則事務A讀取的是無效的資料。這跟不可重複讀類似,但是第二個事務不需要執行提交。
事務1 | 事務2 |
SELECT * FROM users WHERE id=1 |
|
UPDATE users SET age=21 WHERE id=1; |
|
SELECT * FROM users WHERE id=1; |
|
COMMIT; /* lock-based DIRTY READ */ |
【小結】
併發操作引起的問題還是比較常見的,在多使用者共享系統中,許多事務可能同時對同意資料進行操作,此時可能會破環資料庫的完整性
資料庫真是一個神奇的東西,對於資料庫的學習還在探索中,遇到問題不斷總結不斷積累,期待自己變成大神的一天
以上僅代表我的個人觀點,如有不同見解,歡迎指正