1. 程式人生 > >mysql中的get_lock鎖機制解析

mysql中的get_lock鎖機制解析

select get_lock(key, timeout) from dual;
select release_lock(key) from dual;
2. 概述

(1)get_lock會按照key來加鎖,別的客戶端再以同樣的key加鎖時就加不了了,處於等待狀態。
(2)當呼叫release_lock來釋放上面加的鎖或客戶端斷線了,上面的鎖才會釋放,其它的客戶端才能進來。

以下定義兩個客戶端,A1和A2。

建立表:

create table test_lock(
    id int,
    name varchar(50),
    address varchar(50)
);
insert into test_lock values(1,'tt','aaaaaaaaaaaaaaaaaaaa');

A1:

select get_lock('key_lock', 100);

update test_lock set name = 'tt2', address = 'aaaaaaaaaaaaaaaaaaaa' where id = 1; #只更新name列

select release_lock('key_lock');

A2:

select get_lock('key_lock', 100);

update test_lock set name = 'tt'
, address = 'bbbbbbbbbbbbbbbbbbbbbbb' where id = 1;
#只更新address列 select release_lock('key_lock');

執行A1的第一條語句後執行A2的第一條語句會發現一直卡在那裡,直接執行了A1的最後一條語句(或過期或斷線)為止才能繼續執行A2的語句。

如果按上面的順序分別執行了A1和A2中的語句,則最後表中的資料是按A2的第二語句更新那樣的顯示,這種結果當然不是我們想要的,實際專案中,應該是先查出來id為1的資料,把某列更新的值set進去(針對Java),再執行更新,這樣所有的更新結果都是正確的。

(1)這種方式對於更新所有列比較有效,但是得把查詢的語句也放在鎖內執行;
(2)這種方式當客戶端無故斷線了會自動釋放鎖,比較好,不像redis鎖那樣,如果加完鎖斷了,那麼鎖一直在;
(3)這種方式是針對鎖內的所有操作加鎖,並不針對特定表或特定行,所以使用了同一個Key的鎖但不同的操作都會共用一把鎖,會導致效率低下;
(4)如果查詢語句放在鎖之前,則資料可能是舊的,更新之後會把查詢之後更新之前別的客戶端更新的資料覆蓋掉;

A1客戶端:

execute("select get_lock('key_lock', 100)");
User user = queryUser(1);
user.setName("tt1");
updateUser(user);
execute("select release_lock('key_lock')");

A2客戶端:

execute("select get_lock('key_lock', 100)");
User user = queryUser(1);
user.setAddress("bbbbbbbbbbbbbb");
updateUser(user);
execute("select release_lock('key_lock')");

按照以上這種方式操作則兩條更新語句都是正確的,最後的結果應該是
name = ‘tt1’,
address = ‘bbbbbbbbbbbbbb’