數據庫隔離機制


 

所謂的數據庫事務操作其實就是一組原子性的操作,要么全部操作成功,要么全部操作失敗。

    並行事務的四大問題:
    1.更新丟失:和別的事務讀到相同的東西,各自寫,自己的寫被覆蓋了。(誰寫的快誰的更新就丟失了)
    2.臟讀:讀到別的事務未提交的數據。(萬一回滾,數據就是臟的無效的了)
    3.不可重復讀:兩次讀之間有別的事務修改。
    4.幻讀:兩次讀之間有別的事務增刪。

    對應隔離級別
    1.READ UNCOMMITTED:讀未提交,不處理。
    2.READ COMMITTED:讀已提交,只讀提交的數據,無臟讀;
    3.REPEATABLE READ:可重復讀,加行鎖,兩次讀之間不會有修改,無臟讀無重復讀;
    4.SERIALIZABLE: 串行化,加表鎖,全部串行,無所有問題。

 

 

  1.READ UNCIMMITTED(未提交讀)
        事務還沒提交,而別的事務可以看到他其中修改的數據的后果,也就是臟讀。

  2.READ COMMITTED(提交讀)
        首先大多數數據庫系統的默認隔離級別是READ COMMITTED,這種隔離級別就是一個事務的開始,只能看到已經完成的事務的結果,正在執行的,是無法被其他事務看到的。這種級別會出現讀取舊數據的現象

  3.REPEATABLE READ(可重復讀)
        REPEATABLE READ解決了臟讀的問題,該級別保證了每行的記錄的結果是一致的,也就是上面說的讀了舊數據的問題,但是卻無法解決另一個問題,幻行,顧名思義就是突然蹦出來的行數據。
指的就是某個事務在讀取某個范圍的數據,但是另一個事務又向這個范圍的數據去插入數據,導致多次讀取的時候,數據的行數不一致。

  4.SERIALIZABLE(可串行化)
   SERIALIZABLE是最高的隔離級別,它通過強制事務串行執行(注意是串行),避免了前面的幻讀情況,由於他大量加上鎖,導致大量的請求超時,
因此性能會比較低下,在需要數據一致性且並發量不需要那么大的時候才可能考慮這個隔離級別。

 

下面是各個隔離級別的原理:

READ_UNCOMMITED 的原理:

 

1,事務對當前被讀取的數據不加鎖;
2,事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加 行級共享鎖,直到事務結束才釋放。

下面分別對應上面1,2產生的表現:

1,事務1讀取某行記錄時,事務2也能對這行記錄進行讀取、更新;當事務2對該記錄進行更新時,事務1再次讀取該記錄,能讀到事務2對該記錄的修改版本,即使該修改尚未被提交。
2,事務1更新某行記錄時,事務2不能對這行記錄做更新,直到事務1結束。

 

READ_COMMITED 的原理:

1,事務對當前被讀取的數據加 行級共享鎖(當讀到時才加鎖),一旦讀完該行,立即釋放該行級共享鎖;
2,事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加 行級排他鎖,直到事務結束才釋放。

表現

  1,事務1讀取某行記錄時,事務2也能對這行記錄進行讀取、更新;當事務2對該記錄進行更新時,事務1再次讀取該記錄,讀到的只能是事務2對其更新前的版本,要不就是事務2提交后的版本。
  2,事務1更新某行記錄時,事務2不能對這行記錄做更新,直到事務1結束。

REPEATABLE READ 的原理:

1,事務在讀取某數據的瞬間(就是開始讀取的瞬間),必須先對其加 行級共享鎖,直到事務結束才釋放;
2,事務在更新某數據的瞬間(就是發生更新的瞬間),必須先對其加 行級排他鎖,直到事務結束才釋放。

表現

  1,事務1讀取某行記錄時,事務2也能對這行記錄進行讀取、更新;當事務2對該記錄進行更新時,事務1再次讀取該記錄,讀到的仍然是第一次讀取的那個版本。
  2,事務1更新某行記錄時,事務2不能對這行記錄做更新,直到事務1結束。

SERIALIZABLE 的原理:

1,事務在讀取數據時,必須先對其加 表級共享鎖 ,直到事務結束才釋放;
2,事務在更新數據時,必須先對其加 表級排他鎖 ,直到事務結束才釋放。

表現

  1,事務1正在讀取A表中的記錄時,則事務2也能讀取A表,但不能對A表做更新、新增、刪除,直到事務1結束。
  2,事務1正在更新A表中的記錄時,則事務2不能讀取A表的任意記錄,更不可能對A表做更新、新增、刪除,直到事務1結束。

 

這里咋一看覺得能理解,但細想沒有特別搞清,主要是這里面出現的幾種鎖,下面是數據庫涉及和本文涉及到的鎖的解釋:
這里只針對MySQL,其他的可能有細微差別,但總體都是一個思想;
MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支持不同的鎖機制。比如,

MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking)。
InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認情況下是采用行級鎖。
所有的鎖都是綁定在數據庫的索引機制上的!!!
首先鎖可以分為: 

表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。
頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般。

而除了粒度,鎖根據模式分為:

共享鎖(S):發生在數據查找之前,多個事務的共享鎖之間可以共存

排他鎖(X):發生在數據更新之前,排他鎖是一個獨占鎖,與其他鎖都不兼容

更新鎖(U):發生在更新語句中,更新鎖用來查找數據,當查找的數據不是要更新的數據時轉化為S鎖,當是要更新的數據時轉化為X鎖

意向鎖:發生在較低粒度級別的資源獲取之前,表示對該資源下低粒度的資源添加對應的鎖,意向鎖有分為:
    意向共享鎖(IS) ,意向排他鎖(IX),意向更新鎖(IU),共享意向排他鎖(SIX),共享意向更新鎖(SIU),更新意向排他鎖(UIX)

意向鎖又分為

意向共享鎖(IS):事務打算給數據行加行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的IS鎖。
意向排他鎖(IX):事務打算給數據行加行排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的IX鎖。

共享鎖/排他鎖/更新鎖一般作用在較低級別上,例如數據行或數據頁,意向鎖一般作用在較高的級別上,例如數據表或數據。鎖是有層級結構的,若在數據行上持有排他鎖的時候,則會在所在的數據頁上持有意向排他鎖. 在一個事務中,可能由於鎖持有的時間太長或個數太多,出於節約資源的考慮,會造成鎖升級;

我理解的就以最后一個SERIALIZABLE來說,開始時是設置的表級共享鎖,分為表級別的而且是共享鎖,表級別就是作用於整個表,不是行級別!而共享鎖,則說明了其他事務也是共享鎖的情況下可以共享這個表!雖然僅限於讀,但這樣也可能存在臟讀等情況的存在,而如果換成表級排它鎖,那么第一個事務在使用了這個鎖之后,那其他事務連這個表的讀的權限也沒有,從根本上避免了各種可能的問題。

最后總結一下各個索引引擎的情況: 

1.InnoDB(MySQL默認存儲引擎 從版本5.5.5開始)
支持事務,行級鎖,以及外鍵,擁有高並發處理能力。但是在創建索引和加載數據時,比MyISAM慢。默認的隔離級別是Repeatable Read(可重復讀)

2.MyISAM
不支持事務和行級鎖。所以速度很快,性能優秀。可以對整張表加鎖,支持並發插入,支持全文索引。

3.MEMORY
支持Hash索引,內存表,Memory引擎將數據存儲在內存中,表結構不是存儲在內存中的,查詢時不需要執行磁盤I/O操作,所以要比MyISAM和InnoDB快很多倍,
但是數據庫斷電或是重啟后,表中的數據將會丟失,表結構不會丟失。

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM