資料庫鎖整理

2021-08-22 14:46:24 字數 4321 閱讀 1850

在了解資料庫索引之前,首先了解一下資料庫索引的資料結構基礎,b+tree

b+tree是乙個n叉樹,每個節點有多個葉子節點,一顆b+樹包含根節點,內部節點,葉子節點。根節點可能是乙個葉子節點,也可能是乙個包含兩個或兩個以上葉子節點的節點。

b+tree的性質:

n棵子tree的節點包含n個關鍵字,不用來儲存資料而是儲存資料的索引。

所有的葉子結點中包含了全部關鍵字的資訊,及指向含這些關鍵字記錄的指標,且葉子結點本身依關鍵字的大小自小而大順序鏈結。

所有的非終端結點可以看成是索引部分,結點中僅含其子樹中的最大(或最小)關鍵字。

b+tree結構原型圖大概如下(引用):

由於b+tree的性質, 它通常被用於資料庫和作業系統的檔案系統中。ntfs, reiserfs, nss, xfs, jfs, refs 和bfs等檔案系統都在使用b+樹作為元資料索引,因為b+ 樹的特點是能夠保持資料穩定有序,其插入與修改擁有較穩定的對數時間複雜度(b+ 樹元素自底向上插入)。

索引的原理:

對要查詢的字段建立索引其實就是把該字段按照一定的方式排序;建立的索引只對該字段有用,如果查詢的字段改變,那麼這個索引也就無效了,比如圖書館的書是按照書名的第乙個字母排序的,那麼你想要找作者叫張三的就不能用改索引了;還有就是如果索引太多會降低查詢的速度。

索引是優缺點:   

首先明白為什麼索引會增加速度,db在執行一條sql語句的時候,預設的方式是根據搜尋條件進行全表掃瞄,遇到匹配條件的就加入搜尋結果集合。如果我們對某一欄位增加索引,查詢時就會先去索引列表中一次定位到特定值的行數,大大減少遍歷匹配的行數,所以能明顯增加查詢的速度。那麼在任何時候都應該加索引麼?

這裡有幾個反例:

如果每次都需要取到所有表記錄,無論如何都必須進行全表掃瞄了,那麼是否加索引也沒有意義了。

對非唯一的字段,例如「性別」這種大量重複值的字段,增加索引也沒有什麼意義。

對於記錄比較少的表,增加索引不會帶來速度的優化反而浪費了儲存空間,因為索引是需要儲存空間的,而且有個致命缺點是對於update/insert/delete的每次執行,欄位的索引都必須重新計算更新。所以並不是任何情況下都改建立索引的

唯一性索引,可以保證資料庫表中每一行資料的唯一性。

如果您指定了on duplicate key update,並且插入行後會導致在乙個unique索引或primary key中出現重複值,則執行舊行update。例如,如果列a被定義為unique,並且包含值1,則以下兩個語句具有相同的效果:

mysql>insert into table (a,b,c) values (1,2,3) on duplicate key update c=c+1;

mysql>update table set c=c+1 where a=1;

如果行作為新記錄被插入,則受影響行的值為1;如果原有的記錄被更新,則受影響行的值為2。

注釋:如果列b也是唯一列,則insert與此update語句相當:

mysql>update table set c=c+1 where a=1 or b=2 limit 1;
如果a=1 or b=2與多個行向匹配,則只有乙個行被更新。通常,您應該盡量避免對帶有多個唯一關鍵字的表使用on duplicate key子句。

您可以在update子句中使用values(col_name)函式從insert...update語句的insert部分引用列值。換句話說,如果沒有發生重複關鍵字衝突,則update子句中的values(col_name)可以引用被插入的col_name的值。本函式特別適用於多行插入。values()函式只在insert...update語句中有意義,其它時候會返回null。

示例:

mysql>insert into table (a,b,c) values (1,2,3),(4,5,6)

->on duplicate key update c=values(a)+values(b);

本語句與以下兩個語句作用相同:

mysql>insert into table (a,b,c) values (1,2,3)

->on duplicate key update c=3;

mysql>insert into table (a,b,c) values (4,5,6)

->on duplicate key update c=9;

當您使用on duplicate key update時,delayed選項被忽略。

根據不同的鎖的作用域我們可以把資料庫的鎖分為三種,分別為:

不同的作用域對併發效能是有很大影響的,比如說如果資料庫的插入都是使用表鎖,那在大量使用者對某張表進行插入讀取操作的話,同時只能有乙個使用者可以訪問該錶,那併發量肯定就是慘不忍睹了。

在樂觀鎖中,我們有3種常用的做法來實現:

第一種就是在資料取得的時候把整個資料都copy到應用中,在進行提交的時候比對當前資料庫中的資料和開始的時候更新前取得的資料。當發現兩個資料一模一樣以後,就表示沒有衝突可以提交,否則則是併發衝突,需要去用業務邏輯進行解決。

第二種樂觀鎖的做法就是採用版本戳,這個在hibernate中得到了使用。採用版本戳的話,首先需要在你有樂觀鎖的資料庫table上建立乙個新的column,比如為number型,當你資料每更新一次的時候,版本數就會往上增加1。比如同樣有2個session同樣對某條資料進行操作。兩者都取到當前的資料的版本號為1,當第乙個session進行資料更新後,在提交的時候檢視到當前資料的版本還為1,和自己一開始取到的版本相同。就正式提交,然後把版本號增加1,這個時候當前資料的版本為2。當第二個session也更新了資料提交的時候,發現資料庫中版本為2,和一開始這個session取到的版本號不一致,就知道別人更新過此條資料,這個時候再進行業務處理,比如整個transaction都rollback等等操作。在用版本戳的時候,可以在應用程式側使用版本戳的驗證,也可以在資料庫側採用trigger(觸發器)來進行驗證。不過資料庫的trigger的效能開銷還是比較的大,所以能在應用側進行驗證的話還是推薦不用trigger。

第三種做法和第二種做法有點類似,就是也新增乙個table的column,不過這次這個column是採用timestamp型,儲存資料最後更新的時間。在oracle9i以後可以採用新的資料型別,也就是timestamp with time zone型別來做時間戳。這種timestamp的資料精度在oracle的時間型別中是最高的,精確到微秒(還沒與到納秒的級別),一般來說,加上資料庫處理時間和人的思考動作時間,微秒級別是非常非常夠了,其實只要精確到毫秒甚至秒都應該沒有什麼問題。和剛才的版本戳類似,也是在更新提交的時候檢查當前資料庫中資料的時間戳和自己更新前取到的時間戳進行對比,如果一致則ok,否則就是版本衝突。如果不想把**寫在程式中或者由於別的原因無法把**寫在現有的程式中,也可以把這個時間戳樂觀鎖邏輯寫在trigger或者儲存過程中

悲觀鎖也稱之為互斥鎖,可以寫為x鎖,指的是同時只能有乙個事務可以對某個資源進行訪問操作。如果有兩個事務同時要操作某張表,我們稱之為事務a和事務b,如果事務a獲得了這張表的表鎖,那事務b只能等待事務a釋放了這個鎖之後才能對該錶進行操作。

資料庫的insert,update操作預設是採用互斥鎖進行加鎖,讀取select則不是,如果要對select操作使用互斥鎖,可以這樣寫

select * from table where id = 1 for update
共享鎖是一種樂觀鎖,可以寫為s鎖,在資料庫中共享鎖的作用主要是針對讀取操作的。如果讀取操作使用x鎖的話,併發量會非常低,所以資料庫提供了共享鎖s鎖,提高讀取操作的併發效能,多個事務可以同時持有乙個資源的s鎖,不像x鎖,同時只能有乙個事務持有。

舉個例子:

事務a和事務b對錶table進行訪問,事務a想檢視id = 1的行資訊

select * from table where id = 1 lock in share mode
如果當前id = 1的行對應的x鎖沒有被其他事務獲取,那事務a就順利的獲得了該行的s鎖。

現在事務b也想檢視id = 1 的行資訊,會怎麼樣?

select * from table where id = 1 lock in share mode
現在持有該行鎖的只有事務a,持有的是s鎖,所以事務b也可以獲取該行的s鎖,兩個事務可以併發的讀取id = 1的行。

這個和之前所說的樂觀鎖實現是有區別的,最大的不同就是讀取的時候共享鎖是要真的去持有鎖,但是樂觀鎖只是實現了一種cas模式,但是並讀取的時候沒有真的持有鎖。

資料庫(2)資料庫鎖

這一段時間一直在學習關係型資料庫,準備寫乙個小專題來總結一下這一段時間的學習結果。二.事物隔離等級和鎖的關係 網上很多部落格都是直接說了一連串的鎖,什麼悲觀鎖樂觀鎖,什麼讀寫鎖,什麼排他鎖共享鎖。說的不僅語焉不詳,而且分類紊亂,希望看到這篇文章能幫助你理清思路。從鎖的實現方式來看,鎖可以分為悲觀鎖和...

mysql資料庫鎖 MySQL資料庫的鎖機制

在併發訪問情況下,很有可能出現不可重複讀等等讀現象。為了更好的應對高併發,封鎖 時間戳 樂觀併發控制 樂觀鎖 悲觀併發控制 悲觀鎖 都是併發控制採用的主要技術方式。鎖分類 按操作劃分 dml鎖,ddl鎖 按鎖的粒度劃分 表級鎖 行級鎖 頁級鎖 按鎖級別劃分 共享鎖 排他鎖 按加鎖方式劃分 自動鎖 顯...

資料庫鎖基礎

前幾天看過資料庫鎖的介紹,當時雖說看完了,似懂非懂,還記得有次筆試題目,估計也錯了,最近看過高併發性的資料維護課程後,現在翻看鎖基礎,豁然開朗,現整理筆記,及個人理解 sql2005鎖隔離級別有4種,read uncommit read commit,repeatable read 可重複讀,ser...