在php與數據庫的交互中,如果並發量大,並且都去進行數據庫的修改的話,就有一個問題需要注意.數據的鎖問題.就會牽扯數據庫的事務跟隔離機制
數據庫事務依照不同的事務隔離級別來保證事務的ACID特性,也就是說事務不是一開啟就能解決所有並發問題。通常情況下,這里的並發操作可能帶來四種問題:
- 更新丟失:一個事務的更新覆蓋了另一個事務的更新,這里出現的就是丟失更新的問題。
- 臟讀:一個事務讀取了另一個事務未提交的數據。
- 不可重復讀:一個事務兩次讀取同一個數據,兩次讀取的數據不一致。
- 幻象讀:一個事務兩次讀取一個范圍的記錄,兩次讀取的記錄數不一致。
通常數據庫有四種不同的事務隔離級別:
隔離級別 | 臟讀 | 不可重復讀 | 幻讀 |
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable read | × | × | √ |
Serializable | × | × | × |
大多數數據庫的默認的事務隔離級別是提交讀(Read committed),而MySQL的事務隔離級別是重復讀(Repeatable read)。對於丟失更新,只有在序列化(Serializable)級別才可得到徹底解決。不過對於高性能系統而言,使用序列化級別的事務隔離,可能引起死鎖或者性能的急劇下降。因此使用悲觀鎖和樂觀鎖十分必要。 並發系統中,悲觀鎖(Pessimistic Locking)和樂觀鎖(Optimistic Locking)是兩種常用的鎖:
- 悲觀鎖認為,別人訪問正在改變的數據的概率是很高的,因此從數據開始更改時就將數據鎖住,直到更改完成才釋放。悲觀鎖通常由數據庫實現(使用SELECT...FOR UPDATE語句)。
- 樂觀鎖認為,別人訪問正在改變的數據的概率是很低的,因此直到修改完成准備提交所做的的修改到數據庫的時候才會將數據鎖住,完成更改后釋放
***
以mysql為例子:
myisam存儲引擎使用表縮
innodb使用行鎖(明確指定了主鍵的情況下,否則也是表鎖)與表鎖
一般的做法是:
1 開啟事務
2 進行數據更改
3 回滾或者提交
在具體的業務邏輯中,由於隔離機制的不同,導致結果的不同.
樂觀鎖與悲觀鎖使用的也比較多.
由於悲觀鎖在開始讀取時即開始鎖定,因此在並發訪問較大的情況下性能會變差。對MySQL Inodb來說,通過指定明確主鍵方式查找數據會單行鎖定,而查詢范圍操作或者非主鍵操作將會鎖表。