基於資料庫的分布式鎖

2022-01-29 05:35:26 字數 2540 閱讀 1277

使用場景:

某大型**部署是分布式的,訂單系統有三颱伺服器響應使用者請求,生成訂單後統一存放到order_info表;order_info表要求訂單id(order_id)必須是唯一的,那麼三颱伺服器怎麼協同工作來確認order_id的唯一性呢?這時候就要用到分布式鎖了。

分布式鎖的要求:

在了解了使用場景之後,再看一下我們需要的分布式鎖應該是怎樣的(以方法鎖為例)

這把鎖要可重入(防止死鎖)

這把鎖最好是乙個阻塞鎖(根據業務考慮是否需要這條)

有高可用的獲取鎖跟釋放鎖的功能

獲取鎖跟釋放鎖的效能要好

實現方式:

分布式鎖的實現分為3種,基於資料庫的,基於快取的跟基於zookeeper的。接下來我們對這三種方式進行實現。

基於資料庫的分布式鎖:

大概原理:直接建立一張鎖表,當要鎖住某個方法或者資源時,就在該表中增加一條記錄,想要釋放的時候就刪除這條記錄。

create table `methodlock` (

`id` int(11) not null auto_increment comment '主鍵',

`method_name` varchar(64) not null default '' comment '鎖定的方法名',

`mydesc` varchar(1024) not null comment '備註資訊',

`update_time` timestamp not null default current_timestamp on update current_timestamp,

primary key (`id`),

unique key `uidx_method_name` (`method_name`) using btree

) engine=innodb default charset=utf8;

當我們想要鎖住某個方法時,執行以下sql:

insert into methodlock(method_name,desc) values ('具體方法名','描述');

以上的簡單實現有幾個問題:

1、這把鎖依賴資料庫的可用性,如果資料庫是乙個單點,一旦掛掉,會導致業務系統不可用;

2、這把鎖沒有失效時間,一旦解鎖操作失敗,會導致鎖一直存留在資料庫中,其它執行緒無法獲得鎖;

3、這把鎖只能是非阻塞的,因為資料的insert操作一旦插入失敗就直接報錯,沒有獲得鎖的執行緒不會進入排隊佇列,想要再次獲得鎖就要再次觸發獲得鎖的操作;

4、這把鎖是非重入的,同一執行緒在沒有釋放鎖之前無法再次獲得該鎖,因為表中資料已經存在了。

當然上面的問題也是可以解決的:

1、單點問題,兩個資料庫,雙向同步,一旦掛掉切換到另乙個上;

2、失效時間,做乙個定時任務,每隔多長時間清理超時資料;

3、非阻塞問題,程式寫for迴圈多次嘗試,直至獲取到鎖為止;

4、非重入,增加乙個字段,記錄獲取所的ip跟執行緒資訊,下次查詢的時候如果有,則直接給鎖;

示例**:

獲取鎖:

public boolean lock());

}catch (exception e)

if(result == 1)

return false;

}

釋放鎖:

public boolean unlock());

if(rows == 1)else

}

兩個執行緒,模擬兩個客戶端進行測試:

public void testlock() catch (interruptedexception e) 

system.out.println("t1釋放鎖了");

mysqllock.unlock();}}

});thread t2 = new thread(new runnable() catch (interruptedexception e)

trylock();

}//多次嘗試獲取鎖

private boolean trylock()else catch (interruptedexception e)

trylock();

mysqllock.unlock();

}return flag;

}});

t1.start();

t2.start();

try catch (interruptedexception e)

}

輸出結果:

t1拿到鎖,獲取的訂單id為:1

t2獲取鎖失敗,再次嘗試

t2獲取鎖失敗,再次嘗試

t2獲取鎖失敗,再次嘗試

t2獲取鎖失敗,再次嘗試

t2獲取鎖失敗,再次嘗試

t1釋放鎖了

t2拿到鎖,獲取訂單id為:2

可以看到,的確是t2等t1釋放鎖後才拿到了鎖進行了業務操作。

基於資料庫實現分布式鎖

多個程序 多個執行緒訪問共同元件資料庫.通過selec.for update訪問同一條資料 for update鎖定資料,其他執行緒只能等待 此時只有乙個操作可以對資料進行修改,而其他人不能夠對該資料進行修改操作,但可以檢視 select from distribute lock where bus...

基於資料庫悲觀鎖的分布式鎖

基於synchronized和reentrantlock鎖都只限於在單體架構中使用,當出現分布式跨jvm的情況,需要使用分布式鎖來解決跨jvm的問題。通過select for update 訪問同一條資料 for update 鎖定資料,其他執行緒只能等待 1.select autocommit 查...

基於資料庫的分布式鎖實現

一 基於資料庫表 要實現分布式鎖,最簡單的方式可能就是直接建立一張鎖表,然後通過操作該表中的資料來實現了。當我們要鎖住某個方法或資源的時候,我們就在該表中增加一條記錄,想要釋放鎖的時候就刪除這條記錄。建立這樣一張資料庫表 create table methodlock id int 11 not n...