mysql中的get_lock鎖機制解析

mysql中的get_lock鎖機制解析

mysql> SELECT GET_LOCK('MySQL', 10) ; 返回結果爲1,說明成功得到鎖
+-----------------+
| ci_session_lock |
+-----------------+
| 1 |
+-----------------+
1 row in set (0.00 sec)

mysql>select RELEASE_LOCK('MySQL') ;
+----------------------------------------------------------+
| RELEASE_LOCK('MySQL') |
+----------------------------------------------------------+
| 1 |
+----------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT IS_USED_LOCK('MySQL') ; 返回結果爲當前連接ID,表示名稱爲'MySQL'的鎖正在被使用。
+-----------------+
| ci_session_lock |
+-----------------+
| 8 |
+-----------------+
1 row in set (0.00 sec)

mysql> SELECT IS_FREE_LOCK('MySQL') ; 返回結果爲0,說明名稱爲'MySQL'的鎖正在被使用。
+-----------------+
| ci_session_lock |
+-----------------+
| 0 |
+-----------------+
1 row in set (0.00 sec)

創建表:

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

  2. 舉個Java例子的僞代碼
    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’

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章