2013年4月18日 星期四

MySQL 鎖定資料表 (LOCK TABLES)

MySQL 如果是用 MyISAM 資料表,因為 MyISAM 沒有交易功能。若要避免多個連線交互執行 SQL 指令,造成資料錯亂,只好使用鎖定資料表的方式。

官網資料:http://dev.mysql.com/doc/refman/5.7/en/lock-tables.html

[鎖定的指令]

  • LOCK TABLES 資料表 READ;
    讀取:全部連線(session)都可讀取。
    寫入:全部連線都不可寫入,包括自己也不可寫入
    取得條件:無其他連線取得 WRITE LOCK 的時候。
  • LOCK TABLES 資料表 READ LOCAL;
    讀取:全部連線(session)都可讀取。
    寫入:全部連線都不可寫入,包括自己也不可寫入。但可 INSERT 不影響現有資料的 SQL 指令。
    取得條件:無其他連線取得 WRITE LOCK 的時候。
  • LOCK TABLES 資料表 WRITE;
    讀取:自己可讀取,其他使用者不行。
    寫入:自己可寫入,其他使用者不行。
    取得條件:無其他連線取得 WRITE LOCK、READ LOCK 的時候。
  • LOCK TABLES 資料表 LOW_PRIORITY WRITE;
    讀取:自己可讀取,其他使用者不行。
    寫入:自己可寫入,其他使用者不行。
    取得條件:無其他連線取得 WRITE LOCK、READ LOCK 的時候。
    LOW_PRIORITY:等待其他鎖定被釋放的期間,允許其他人取得鎖定。MySQL 5.6.5 以後此設定已無效
  • 若鎖定過程,須操作多個資料表時,須鎖定多個資料表,否則會出現 was not locked with LOCK TABLES 錯誤。
    同時鎖定兩個資料表:LOCK TABLES aaa WRITE, bbb WRITE
  • 若鎖定過程,會另外將資料表命名別名,須連同別名也一同鎖定,否則會出現 was not locked with LOCK TABLES 錯誤
    同時鎖定資料表別名:LOCK TABLES aaa WRITE, aaa AS a WRITE
  • 範例
    下圖為第1個連線,使用 WRITE 的方式,先 LOCK 住 aa 資料表。自己還是能讀取資料表。

    下圖為第2個連線,要讀取 aa 資料表時,因為資料表已被第一個連線 LOCK,所以無法讀取,一直在等待 aa 資料表解除鎖定。

[解鎖的指令]

  •  UNLOCK TABLES;
    範例:
    LOCK TABLES test READ;
    --
    --其他 SQL 指令
    --
    UNLOCK TABLES;

[其他相關指令]

  • GET_LOCK(鎖定名稱, 等待幾秒)
    SELECT GET_LOCK('aa',10); --最多等 10 秒,嘗試取得名稱為"aa"的鎖定
    --成功 select 得到1,失敗得到0

    http://dev.mysql.com/doc/refman/5.6/en/miscellaneous-functions.html#function_get-lock
  • RELEASE_LOCK(鎖定名稱)
    SELECT RELEASE_LOCK('aa'); --釋放名稱為"aa"的鎖定

    http://dev.mysql.com/doc/refman/5.6/en/miscellaneous-functions.html#function_release-lock
  • 當某"名稱"先被其他連線鎖定時。其他連線要用同樣的名稱執行 GET_LOCK() 時會卡住,超過等待時間時,會返回失敗。
  • GET_LOCK 和 RELEASE_LOCK 不實際鎖定資料表,只是提供某名稱是否有人鎖定,所以其他人還是可正常讀寫資料表
    因此,在同時多連線,要避免某些 SQL 指令交錯執行,也可用"鎖定某名稱的方式"來判斷是否有其他連線正在執行這些的 SQL 指令,以確保期執行期間,不會有其他連線進來交互執行這些 SQL 指令。

沒有留言:

張貼留言