1. 程式人生 > >Mysql鎖定表/解鎖句法

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 中,你對該表需要有 SELECTinsertDELETEUPDATE 許可權。

使用 LOCK TABLES 的主要原因是,仿效事務處理或在更新表時得到更快的速度。此後會有更詳細的描述。

如果一個執行緒在一個表上得到一個 READ 鎖,該執行緒 (和所有其它執行緒) 只能從表中讀取。如果一個執行緒在一個表上得到一個 WRITE 鎖,那麼只有擁有這個鎖的執行緒可以從表中讀取和寫表。其它的執行緒被阻塞。

READ LOCALREAD 之間的不同就在於,當鎖被載入時,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 工作如下:

  1. 以內部定義的次序排序所有被鎖定的表 (從使用者立場說,該次序是不明確的)。
  2. 如果一個表被以一個讀鎖和一個寫鎖鎖定,將寫鎖放在讀鎖之前。
  3. 一次只鎖定一個表,只到執行緒得到所有的鎖定。

這個方案是為了確保,表鎖定死鎖釋放。 對於這個模式你仍然有些其它事情需要知道:

如果你對一個表使用一個 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,將可能發生在 SELECTUPDATE 語句執行期間有另外一個執行緒可能在 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 不是事務安全的,在嘗試鎖定一個表之前,將自動地提交所有的活動事務。