分佈式系統核心要求:分佈式鎖實現之關係型數據庫

利用關係型數據庫特性:實現排它鎖(insert唯一約束)和樂觀鎖(update version一致性)。

排他鎖

 表結構


獲取鎖

INSERT INTO method_lock (method_name, desc) VALUES ('methodName', 'methodName');


對method_name做了唯一性約束,這裏如果有多個請求同時提交到數據庫的話,數據庫會保證只有一個操作可以成功。

樂觀鎖

表結構

DROP TABLE IF EXISTS `method_lock`;
CREATE TABLE `method_lock` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `method_name` varchar(64) NOT NULL COMMENT '鎖定的方法名',
  `state` tinyint NOT NULL COMMENT '1:未分配;2:已分配',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `version` int NOT NULL COMMENT '版本號',
  `PRIMARY KEY (`id`),
  UNIQUE KEY `uidx_method_name` (`method_name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='鎖定中的方法';


先獲取鎖的信息

select id, method_name, state,version from method_lock where state=1 and method_name='methodName';

佔有鎖

update t_resoure set state=2, version=2, update_time=now() where method_name='methodName' and state=1 and version=2;

如果沒有更新影響到一行數據,則說明這個資源已經被別人佔位了。

缺點:

    1、這把鎖強依賴數據庫的可用性,數據庫是一個單點,一旦數據庫掛掉,會導致業務系統不可用。
    2、這把鎖沒有失效時間,一旦解鎖操作失敗,就會導致鎖記錄一直在數據庫中,其他線程無法再獲得到鎖。
    3、這把鎖只能是非阻塞的,因爲數據的insert操作,一旦插入失敗就會直接報錯。沒有獲得鎖的線程並不會進入排隊隊列,要想再次獲得鎖就要再次觸發獲得鎖操作。
    4、這把鎖是非重入的,同一個線程在沒有釋放鎖之前無法再次獲得該鎖。因爲數據中數據已經存在了。

解決方案:
     1、數據庫是單點?搞兩個數據庫,數據之前雙向同步。一旦掛掉快速切換到備庫上。
     2、沒有失效時間?只要做一個定時任務,每隔一定時間把數據庫中的超時數據清理一遍。
     3、非阻塞的?搞一個while循環,直到insert成功再返回成功。
     4、非重入的?在數據庫表中加個字段,記錄當前獲得鎖的機器的主機信息和線程信息,那麼下次再獲取鎖的時候先查詢數據庫,如果當前機器的主機信息和線程信息在數據庫可以查到的話,直接把鎖分配給他就可以了。
————————————————
版權聲明:本文爲CSDN博主「1Vincent」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/wuzhiwei549/article/details/80692278

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