Mysql鎖定表/解鎖句法
6.7.2 LOCK TABLES/UNLOCK TABLES
句法
LOCK TABLES tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}
[, tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE} ...]
...
UNLOCK TABLES
LOCK TABLES
為當前執行緒鎖定表。UNLOCK TABLES
釋放當前執行緒擁有的所有鎖定。當執行緒發出另一個 LOCK TABLES
,或當與伺服器的連線被關閉時,被當前執行緒鎖定的所有表將被自動地解鎖。
為了在 MySQL 4.0.2 使用 LOCK TABLES
,你必須擁有一個全域性的 LOCK TABLES
許可權和一個在相關表上的 SELECT
許可權。在 MySQL 3.23 中,你對該表需要有 SELECT
、insert
、DELETE
和 UPDATE
許可權。
使用 LOCK TABLES
的主要原因是,仿效事務處理或在更新表時得到更快的速度。此後會有更詳細的描述。
如果一個執行緒在一個表上得到一個 READ
鎖,該執行緒 (和所有其它執行緒) 只能從表中讀取。如果一個執行緒在一個表上得到一個 WRITE
鎖,那麼只有擁有這個鎖的執行緒可以從表中讀取和寫表。其它的執行緒被阻塞。
READ LOCAL
和 READ
之間的不同就在於,當鎖被載入時,READ LOCAL
允許非衝突(non-conflicting) INSERT
語句執行。如果當你載入著鎖時從 MySQL 外部操作資料庫檔案,這將仍不能被使用。
當你使用 LOCK TABLES
是地,你必須鎖定所有你將使用的表,並且必須使用與你的查詢中將使用的別名相同!如果你在一個查詢中多次使用一個表(用別名),你必須為每一個別名獲得一個鎖。
WRITE
鎖通過比 READ
鎖有更高的許可權,以確保更新被儘快地處理。這就意味著,如果一個執行緒獲得一個 READ
鎖,而同時另外一個執行緒請求一個 WRITE
READ
鎖請求將等待直到 WRITE
執行緒得到了鎖並釋放了它。你可以使用 LOW_PRIORITY WRITE
鎖,當該執行緒在等待 WRITE
鎖時,它將允許其它的執行緒獲得 READ
鎖。 你應該只使用 LOW_PRIORITY WRITE
鎖,如果你確信這將是最後一次,當沒有執行緒將擁有 READ
鎖。
LOCK TABLES
工作如下:
- 以內部定義的次序排序所有被鎖定的表 (從使用者立場說,該次序是不明確的)。
- 如果一個表被以一個讀鎖和一個寫鎖鎖定,將寫鎖放在讀鎖之前。
- 一次只鎖定一個表,只到執行緒得到所有的鎖定。
這個方案是為了確保,表鎖定死鎖釋放。 對於這個模式你仍然有些其它事情需要知道:
如果你對一個表使用一個 LOW_PRIORITY WRITE
鎖定,這就意味著,MySQL 將等待這個鎖,直到沒有執行緒請求一個 READ
鎖。當執行緒得到了 WRITE
鎖,並等待獲得鎖定表列表中的下一個表的鎖定時,其它所有的執行緒將等待 WRITE
鎖被釋放。如果這在你的應用程式中會引起一個嚴重的問題,你應該考慮將你的某些錶轉換為事務安全表。
你可以使用 KILL
安全地殺死一個正在表鎖定的執行緒。檢視章節 4.5.5 KILL
句法。
注意,你不應該 鎖定你正在對其使用 INSERT DELAYED
的表。這是因為,在這種情況下,INSERT
是通過單獨的執行緒完成的。
通常,你不需要鎖定任何表,因為所有單 UPDATE
語句都是原子的;其它的執行緒無法干擾當前執行的 SQL 語句。當你無論如何希望鎖定表時,這裡有一些情況:
- 如果你在一束表上執行許多操作,鎖定你將要使用的表,這會更快一些。當然有不利的方面,其它執行緒將不能更新一個
READ
鎖的表,並且沒有其它執行緒要以讀取一個WRITE
鎖的表。 在LOCK TABLES
下,某些事執行得更快一些的原因是,MySQL 將不會轉儲清除被鎖定表鍵高速緩衝,直到UNLOCK TABLES
被呼叫 (通常鍵高速緩衝在每個 SQL 語句後都會被轉儲清除)。這將加速在MyISAM
表上的插入、更新、刪除。 - 如果你在 MySQL 中正在使用一個不支援事務的儲存引擎,如果你希望能確保沒有其它的執行緒會出現在一個
SELECT
和 一個UPDATE
之間,你必須使用LOCK TABLES
。下面的示例顯示為了安全地執行,這裡需要LOCK TABLES
:mysql> LOCK TABLES trans READ, customer WRITE;
不使用
mysql> SELECT SUM(value) FROM trans WHERE customer_id=some_id;
mysql> UPDATE customer SET total_value=sum_from_previous_statement
-> WHERE customer_id=some_id;
mysql> UNLOCK TABLES;LOCK TABLES
,將可能發生在SELECT
和UPDATE
語句執行期間有另外一個執行緒可能在trans
表中插入一行新記錄。
通過使用遞增更新 (UPDATE customer SET value=value+new_value
) 或 LAST_INSERT_ID()
函式,你可以在很多情況下避免使用 LOCK TABLES
。
你也可以使用使用者級鎖定函式 GET_LOCK()
和 RELEASE_LOCK()
解決一些情況,這些鎖被儲存在伺服器上的一個雜湊表中,並以 pthread_mutex_lock()
和 pthread_mutex_unlock()
實現以獲得高速度。檢視章節 6.3.6.2 輔助功能函式。
你可以使用 FLUSH TABLES WITH READ LOCK
命令以讀鎖鎖定所有資料庫中的所有表。檢視章節 4.5.3 FLUSH
句法。如果你有一個可以及時建立檔案快照的檔案系統,例如 Veritas,這將是得到備份的非常方便方式。
注意:LOCK TABLES
不是事務安全的,在嘗試鎖定一個表之前,將自動地提交所有的活動事務。