mysql實(shí)現(xiàn)分布式鎖

純數(shù)據(jù)庫(kù)表實(shí)現(xiàn)方式

首先創(chuàng)建一張表:

CREATE TABLE `methodLock` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `method_name` varchar(64) NOT NULL DEFAULT '' COMMENT '鎖定的方法名',
  `desc` varchar(1024) NOT NULL DEFAULT '備注信息',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '保存數(shù)據(jù)時(shí)間祭玉,自動(dòng)生成',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uidx_method_name` (`method_name `) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='鎖定中的方法';

當(dāng)我們想要鎖住某個(gè)方法時(shí)抒线,執(zhí)行以下SQL:
insert into methodLock(method_name,desc) values (‘method_name’,‘desc’)

因?yàn)槲覀儗?duì)method_name做了唯一性約束,這里如果有多個(gè)請(qǐng)求同時(shí)提交到數(shù)據(jù)庫(kù)的話,數(shù)據(jù)庫(kù)會(huì)保證只有一個(gè)操作可以成功其爵,那么我們就可以認(rèn)為操作成功的那個(gè)線程獲得了該方法的鎖,可以執(zhí)行方法體內(nèi)容。

當(dāng)方法執(zhí)行完畢之后侨歉,想要釋放鎖的話,需要執(zhí)行以下Sql:

delete from methodLock where method_name ='method_name'
上面這種簡(jiǎn)單的實(shí)現(xiàn)有以下幾個(gè)問(wèn)題:

  • 這把鎖強(qiáng)依賴(lài)數(shù)據(jù)庫(kù)的可用性揩魂,數(shù)據(jù)庫(kù)是一個(gè)單點(diǎn)幽邓,一旦數(shù)據(jù)庫(kù)掛掉,會(huì)導(dǎo)致業(yè)務(wù)系統(tǒng)不可用火脉。
  • 這把鎖沒(méi)有失效時(shí)間颊艳,一旦解鎖操作失敗,就會(huì)導(dǎo)致鎖記錄一直在數(shù)據(jù)庫(kù)中忘分,其他線程無(wú)法再獲得到鎖棋枕。
  • 這把鎖只能是非阻塞的,因?yàn)閿?shù)據(jù)的insert操作妒峦,一旦插入失敗就會(huì)直接報(bào)錯(cuò)重斑。沒(méi)有獲得鎖的線程并不會(huì)進(jìn)入排隊(duì)隊(duì)列,要想再次獲得鎖就要再次觸發(fā)獲得鎖操作肯骇。
  • 這把鎖是不可重入的窥浪,同一個(gè)線程在沒(méi)有釋放鎖之前無(wú)法再次獲得該鎖。因?yàn)閿?shù)據(jù)中數(shù)據(jù)已經(jīng)存在了笛丙。

當(dāng)然漾脂,我們也可以有其他方式解決上面的問(wèn)題。

  • 數(shù)據(jù)庫(kù)是單點(diǎn)胚鸯?搞兩個(gè)數(shù)據(jù)庫(kù)骨稿,數(shù)據(jù)之前雙向同步。一旦掛掉快速切換到備庫(kù)上。
  • 沒(méi)有失效時(shí)間坦冠?只要做一個(gè)定時(shí)任務(wù)形耗,每隔一定時(shí)間把數(shù)據(jù)庫(kù)中的超時(shí)數(shù)據(jù)清理一遍
  • 非阻塞的?搞一個(gè)while循環(huán)辙浑,直到insert成功再返回成功激涤。
  • 非重入的?在數(shù)據(jù)庫(kù)表中加個(gè)字段判呕,記錄當(dāng)前獲得鎖的機(jī)器的主機(jī)信息和線程信息倦踢,那么下次再獲取鎖的時(shí)候先查詢(xún)數(shù)據(jù)庫(kù),如果當(dāng)前機(jī)器的主機(jī)信息和線程信息在數(shù)據(jù)庫(kù)可以查到的話侠草,直接把鎖分配給他就可以了硼一。

基于數(shù)據(jù)庫(kù)排他鎖

除了可以通過(guò)增刪操作數(shù)據(jù)表中的記錄以外,其實(shí)還可以借助數(shù)據(jù)中自帶的鎖來(lái)實(shí)現(xiàn)分布式的鎖梦抢。

我們還用剛剛創(chuàng)建的那張數(shù)據(jù)庫(kù)表般贼。可以通過(guò)數(shù)據(jù)庫(kù)的排他鎖來(lái)實(shí)現(xiàn)分布式鎖奥吩。
基于MySql的InnoDB引擎哼蛆,可以使用以下方法來(lái)實(shí)現(xiàn)加鎖操作:

public boolean lock(){
    connection.setAutoCommit(false)
    while(true){
        try{
            result = select * from methodLock where method_name=xxx for update;
            if(result==null){
                return true;
            }
        }catch(Exception e){

        }
        sleep(1000);
    }
    return false;
}

在查詢(xún)語(yǔ)句后面增加for update,數(shù)據(jù)庫(kù)會(huì)在查詢(xún)過(guò)程中給數(shù)據(jù)庫(kù)表增加排他鎖霞赫。當(dāng)某條記錄被加上排他鎖之后腮介,其他線程無(wú)法再在該行記錄上增加排他鎖。(這里再多提一句端衰,InnoDB引擎在加鎖的時(shí)候叠洗,只有通過(guò)索引進(jìn)行檢索的時(shí)候才會(huì)使用行級(jí)鎖,否則會(huì)使用表級(jí)鎖旅东。這里我們希望使用行級(jí)鎖灭抑,就要給method_name添加索引,值得注意的是抵代,這個(gè)索引一定要?jiǎng)?chuàng)建成唯一索引腾节,否則會(huì)出現(xiàn)多個(gè)重載方法之間無(wú)法同時(shí)被訪問(wèn)的問(wèn)題。重載方法的話建議把參數(shù)類(lèi)型也加上)

我們可以認(rèn)為獲得排它鎖的線程即可獲得分布式鎖荤牍,當(dāng)獲取到鎖之后案腺,可以執(zhí)行方法的業(yè)務(wù)邏輯,執(zhí)行完方法之后康吵,再通過(guò)以下方法解鎖:

public void unlock(){
    connection.commit();
}

這里還可能存在另外一個(gè)問(wèn)題劈榨,雖然我們對(duì)method_name 使用了唯一索引,并且顯示使用for update來(lái)使用行級(jí)鎖晦嵌。但是同辣,MySql會(huì)對(duì)查詢(xún)進(jìn)行優(yōu)化拷姿,即便在條件中使用了索引字段,但是否使用索引來(lái)檢索數(shù)據(jù)是由 MySQL 通過(guò)判斷不同執(zhí)行計(jì)劃的代價(jià)來(lái)決定的邑闺,如果 MySQL 認(rèn)為全表掃效率更高,比如對(duì)一些很小的表棕兼,它就不會(huì)使用索引陡舅,這種情況下 InnoDB 將使用表鎖,而不是行鎖伴挚。如果發(fā)生這種情況就悲劇了靶衍。。茎芋。

還有一個(gè)問(wèn)題颅眶,就是我們要使用排他鎖來(lái)進(jìn)行分布式鎖的lock,那么一個(gè)排他鎖長(zhǎng)時(shí)間不提交田弥,就會(huì)占用數(shù)據(jù)庫(kù)連接涛酗。一旦類(lèi)似的連接變得多了,就可能把數(shù)據(jù)庫(kù)連接池?fù)伪?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末偷厦,一起剝皮案震驚了整個(gè)濱河市商叹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌只泼,老刑警劉巖剖笙,帶你破解...
    沈念sama閱讀 212,080評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異请唱,居然都是意外死亡弥咪,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)十绑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)聚至,“玉大人,你說(shuō)我怎么就攤上這事本橙⊥砹耄” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,630評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵勋功,是天一觀的道長(zhǎng)坦报。 經(jīng)常有香客問(wèn)我,道長(zhǎng)狂鞋,這世上最難降的妖魔是什么片择? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,554評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮骚揍,結(jié)果婚禮上字管,老公的妹妹穿的比我還像新娘啰挪。我一直安慰自己,他們只是感情好嘲叔,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布亡呵。 她就那樣靜靜地躺著,像睡著了一般硫戈。 火紅的嫁衣襯著肌膚如雪锰什。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,856評(píng)論 1 290
  • 那天丁逝,我揣著相機(jī)與錄音汁胆,去河邊找鬼。 笑死霜幼,一個(gè)胖子當(dāng)著我的面吹牛嫩码,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播罪既,決...
    沈念sama閱讀 39,014評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼铸题,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了琢感?” 一聲冷哼從身側(cè)響起回挽,我...
    開(kāi)封第一講書(shū)人閱讀 37,752評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎猩谊,沒(méi)想到半個(gè)月后千劈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,212評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牌捷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評(píng)論 2 327
  • 正文 我和宋清朗相戀三年墙牌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暗甥。...
    茶點(diǎn)故事閱讀 38,687評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喜滨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出撤防,到底是詐尸還是另有隱情虽风,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評(píng)論 4 331
  • 正文 年R本政府宣布寄月,位于F島的核電站辜膝,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏漾肮。R本人自食惡果不足惜厂抖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望克懊。 院中可真熱鬧忱辅,春花似錦七蜘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,777評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至损搬,卻和暖如春碧库,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背场躯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,006評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工谈为, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旅挤,地道東北人踢关。 一個(gè)月前我還...
    沈念sama閱讀 46,406評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像粘茄,于是被迫代替她去往敵國(guó)和親签舞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容