數據庫鎖
因為數據庫要解決並發控制問題。在同一時刻,可能會有多個客戶端對同一張表進行操作,比如有的在讀取該行數據,其他的嘗試去刪除它。為了保證數據的一致性,數據庫就要對這種並發操作進行控制,因此就有了鎖的概念。
鎖的分類
從對數據庫操作的類型分
讀鎖(共享鎖):針對同一塊數據,多個讀操作可以同時進行而不會互相影響。由讀表操作加上的鎖,加鎖后其他用戶只能獲取該表或行的共享鎖,不能獲取排它鎖,也就是說只能讀不能寫。
寫鎖(排它鎖):當當前寫操作沒有完成之前,它會阻斷其他寫鎖和讀鎖。由寫表操作加上的鎖,加鎖后其他用戶不能獲取該表或行的任何鎖。
從鎖定的數據范圍分
表鎖:鎖定某個表。
行鎖 :鎖定某行。
為了盡可能 提高數據庫的並發度,每次鎖定的數據范圍越小越好。理論上每次只鎖定當前操作的數據的方案會得到最大的並發度,但是管理鎖是很耗費資源的事情。因此數據庫系統需要在高並發響應和系統性能兩方面進行平衡,這樣就產生了“鎖粒度”的概念。
鎖粒度
表鎖:管理鎖的開銷最小,同時允許的並發量也最小的鎖機制。MyIsam存儲引擎使用的鎖機制。當要寫入數據時,把整個表都鎖上,此時其他讀、寫動作一律等待。在MySql中,除了MyIsam存儲引擎使用這種鎖策略外,MySql本身也使用表鎖來執行某些特定動作,比如alter table.
行鎖:可以支持最大並發的鎖策略。InnoDB和Falcon兩張存儲引擎都采用這種策略。
MySql是一種開放的架構,你可以實現自己的存儲引擎,並實現自己的鎖粒度策略,不像Oracle,你沒有機會改變鎖策略,Oracle采用的是行鎖。從大到小,mysql服務器僅支持表級鎖,行鎖需要存儲引擎完成。粒度越精細,並發性越好。即行鎖的並發性最好,但需要存儲引擎的支持。
數據庫事務有不同的隔離級別,不同的隔離級別對鎖的使用是不同的,鎖的應用最終導致不同事務的隔離級別。
1、事務與鎖是不同的。事務具有ACID(原子性、一致性、隔離性和持久性),鎖是用於解決隔離性的一種機制。
2、事務的隔離級別通過鎖的機制來實現。另外鎖有不同的粒度,同時事務也是有不同的隔離級別的。
3、開啟事務就自動加鎖。
ql規范定義的事務的隔離級別:
1.READ UNCOMMITTED(讀取未提交內容)
所有事務可以看到未提交事務的執行結果,本隔離級別很少用到實際應用中,讀取未提交的數據,又稱為“臟讀”。
2.READ COMMITTED(讀取提交內容)
大多數數據庫的默認隔離級別是此級別,但不是MySQL默認的。一個事務在開始的時候只能看見已提交事務所做的改變。一個事務從開始到提交前所做的任何改變都是不可見的,除非提交。這種隔離級別也稱為不可重復讀。
3.REPEATABLE READ(可重復讀)
此隔離級別是為了解決不可重復讀隔離級別導致的問題即一個事務多個實例並發讀取數據時會看到不同的結果。可重復讀描述的是一個事務在處理數據時,多次查詢此數據得到的結果是一樣的。MySQL的InnoDB存儲引擎通過多版本並發控制(Multi_Version Concurrency Control, MVCC)機制來解決該問題。不過理論上,這會導致另一個棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當用戶讀取某一范圍的數據行時, 另一個事務又在該范圍內插入了新行,當用戶再讀取該范圍的數據行時,會發現有新的“幻影” 行。(幻讀描述的是MVCC不能阻止插入新的數據,導致多次查詢時數據記錄不一致。)
4.SERIALIZABLE(可串行化)
可串行化是最高的隔離級別,它通過強制事務排序,使之不可重讀,解決了幻讀的問題。此隔離級別會在每個讀的數據行上加共享鎖,使用這種隔離級別會產生大量的超時現象,一般實際開發中不會用到。該類型在A客戶端操作test.test1表時會鎖定該數據,如果B客戶端想要操作test.test1就需要等待A客戶端釋放。
這四種隔離級別采取不同的鎖類型來實現,若讀取的是同一個數據的話,就容易發生問題。例如:
臟讀(Drity Read):某個事務已更新一份數據,另一個事務在此時讀取了同一份數據,由於某些原因,前一個RollBack了操作,則后一個事務所讀取的數據就會是不正確的。
不可重復讀(Non-repeatable read):在一個事務的兩次查詢之中數據不一致,這可能是兩次查詢過程中間插入了一個事務更新的原有的數據。
幻讀(Phantom Read):在一個事務的兩次查詢中數據筆數不一致,例如有一個事務查詢了幾列(Row)數據,而另一個事務卻在此時插入了新的幾列數據,先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。
mysql加鎖機制:
根據類型可分為共享鎖(SHARED LOCK)和排他鎖(EXCLUSIVE LOCK)或者叫讀鎖(READ LOCK)和寫鎖(WRITE LOCK)。
根據粒度划分又分表鎖和行鎖。表鎖由數據庫服務器實現,行鎖由存儲引擎實現。
mysql提供了3種事務型存儲引擎,InnDB、NDB Cluster和Falcon。
一個事務執行的任何過程中都可以獲得鎖,但是只有事務提交或回滾的時候才釋放這些鎖。這些都是隱式鎖定,也可以顯式鎖定,InnoDB支持顯式鎖定,例如:
SELECT .... LOCK IN SHARE MODE (加共享鎖)
SELECT .....FOR UPDATE(加排他鎖)
多版本並發控制(重要):
Mysql的事務存儲引擎不是簡單實用行加鎖機制,而是叫多版本並發控制(MVCC)技術,和行加鎖機制關聯實用。以便應對更高的並發,當然是以消耗性能作為代價。
每種存儲引擎對MVCC的實現方式不同,InnoDB引擎的簡單實現方式如下:
InnoDB通過為每個數據航增加兩個隱含值的方式來實現。這兩個隱含值記錄了行的創建時間,以及過期時間。每一行存儲事件發生時的系統版本號。每一次開始一個新事務時版本號會自動加1,每個事務都會保存開始時的版本號,每個查詢根據事務的版本號來查詢結果。
MySQL使用以下幾種機制進行隔離性的實現:
a.鎖機制: 通過使用加鎖機制,使用其它事務無法到讀某事務末提交前的數據更新,解決臟讀問題; mySQL 有:共享鎖,排他鎖,根據粒度,有行鎖,表鎖。
b.MVCC機制: 事務存儲引擎使用多版本並發控制(MVCC)技術,和行加鎖機制關聯使用 。MySQL 的InnoDB,XtraDB 引擎通過 使用MVCC 來解決幻讀問題。
事務與鎖是不同的。事務具有ACID( 原子性、一致性、隔離性和持久性),鎖是用於解決隔離性的一種機制。事務的隔離級別通過鎖的機制來實現。另外鎖有不同的粒度,同時事務也是有不同的隔離級別的(一般有四種:讀未提交Read uncommitted, 讀已提交Read committed, 可重復讀Repeatable read, 可串行化Serializable)。 在具體的程序設計中,開啟事務其實是要數據庫支持才行的,如果數據庫本身不支持事務,那么仍然無法確保你在程序中使用的事務是有效的。 鎖可以分為樂觀鎖和悲觀鎖: 悲觀鎖:認為在修改數據庫數據的這段時間里存在着也想修改此數據的事務; 樂觀鎖:認為在短暫的時間里不會有事務來修改此數據庫的數據; 我們一般意義上講的鎖其實是指悲觀鎖,在數據處理過程中,將數據置於鎖定狀態(由數據庫實現)。 回到你的問題,如果開啟了事務,在事務沒提交之前,別人是無法修改該數據的;如果rollback,你在本次事務中的修改將撤消(不是別人修改的會沒有,因為別人此時無法修改)。當然,前提是你使用的數據庫支持事務。還有一個要注意的是,部分數據庫支持自定義SQL鎖覆蓋事務隔離級別默認的鎖機制,如果使用了自定義的鎖,那就另當別論。 重點:一般事務使用的是悲觀鎖(具有排他性)。