mysql分布式安装可靠读写案列图解,高并发下的分布式锁-mysql篇
前言
不管是在面試中,還是在平時的工作中,高并發(fā)永遠(yuǎn)是衡量一個web工作者能力的重要場景。本篇幅我們主要是來討論在高并發(fā)環(huán)境下我們應(yīng)該如何實現(xiàn)分布式鎖。
實現(xiàn)分布式鎖的方式有比較多,這里主要考慮如何使用mysql實現(xiàn)分布式鎖。
Mysql實現(xiàn)鎖的方法
第一種,使用mysql唯一索引來實現(xiàn):
針對這種實現(xiàn),我們只需要新建一張表,專門用來處理分布式任務(wù),比如新建一張 task的表,里面的唯一索引為 task_name 。
運行流程如下:當(dāng)多個副本同時要搶占一個任務(wù)的鎖的時候,就執(zhí)行一個插入語句(這幾個副本的task_name都是一致的),所以,當(dāng)有一個副本之行插入成功后,后續(xù)的其他插入則會由于唯一索引的問題,導(dǎo)致插入失敗。我們可以根據(jù)插入的影響條數(shù)為0 或者是1 ,判斷是否搶鎖成功。最后搶鎖成功的副本,在任務(wù)執(zhí)行結(jié)束之后,將該條記錄刪除,即把鎖刪除掉。
CREATE TABLE `tests`.`task` (
`task-name` varchar(255) NULL,
`id` int(0) NOT NULL AUTO_INCREMENT,
`ctime` timestamp(0) NULL,
`mtime` timestamp(0) NULL ON UPDATE CURRENT_TIMESTAMP(0),
PRIMARY KEY (`id`),
INDEX `uniq_idx_task_name`(`task-name`)
);
// 副本1執(zhí)行:
INSERT INTO `tests`.`task`(`task-name`, `ctime`, `mtime`) VALUES ('demo1', 1, NULL, NULL);
// 副本2同時執(zhí)行
INSERT INTO `tests`.`task`(`task-name`, `ctime`, `mtime`) VALUES ('demo1', 1, NULL, NULL);
// 以上只會有一個副本執(zhí)行成功,另一個副本會直接失敗
第二種,使用mysql的悲觀鎖
for update 和 for udpate no wait :
使用的前提:基于Innodb,并且在支持事務(wù)的情況下可以使用
當(dāng)某用戶執(zhí)行了 for update 之后,該用戶可以在提交或者放棄事務(wù)之前,對該事務(wù)進(jìn)行查詢和更新,其他用戶只能查詢但不能更新被加鎖的數(shù)據(jù)行。
** select XXXX for update 在執(zhí)行過程中可能會鎖行,也可能會鎖表 。 **
當(dāng)查詢中帶有主鍵的時候,會鎖行;
當(dāng)明確帶有(即是使用的不包括模糊查詢之類的)主鍵,但是查詢沒有結(jié)果的,不會導(dǎo)致鎖表;
當(dāng)查詢中無主鍵或者使用了like之類需要全表掃描的,會導(dǎo)致鎖住整個表;(即使查詢中沒有任何數(shù)據(jù)的時候也會導(dǎo)致鎖表)
另外,select XX for update nowait 與 只有 for update 的區(qū)別是for update ,當(dāng)另一個連接嘗試獲取到鎖的時候,會阻塞在那里等待;如果加了 nowait 的話,當(dāng)獲取不到鎖的時候會直接報錯。
// 為了方便這里借用上上面的task表
// 起一個終端,連接上數(shù)據(jù)庫,然后執(zhí)行以下:
set autocommit = 0;
select * from task for update;
// 等待一段時間后再執(zhí)行;
commit;
此時,另一個終端執(zhí)行,可以發(fā)現(xiàn),執(zhí)行 select的話,可以直接返回,但是update的話會產(chǎn)生阻塞,直到之前的事務(wù)commit(看執(zhí)行時間就可以知道)
image.png
// 如果使用for update nowait;
// 副本1執(zhí)行成功:
select * from task for update nowait;
// 副本2執(zhí)行:
mysql> select * from task for update nowait;
ERROR 3572 (HY000): Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set
//值得注意的是,for update nowait 的話,如果你執(zhí)行 update 操作的話,仍然會阻塞在那里。
第三種,使用樂觀鎖
(區(qū)分下第一種,第一種是針對單點定時任務(wù)的,這里延伸下成加鎖)
使用樂觀鎖的話,可以給表中加一個 version 字段,用于表示該行記錄的版本(如果你想要用 timestamp來做也可以,可以直接使用mysql的字段,那樣你就不用考慮該值的更新)
因此,每次更新的流程是,先 select 獲取到一個version(比如是3) 然后再進(jìn)行 update ,查詢中在原來的基礎(chǔ)上多加一個 and version = 3, 如果在select 和 update 之間有個第三方操作了數(shù)據(jù)庫并且操作成功了,此刻version變成了4,那么你進(jìn)行這次update的時候 update XXX where XXX and version = 3的時候,更新就會失敗,那么就不會影響。
結(jié)語
以上就是mysql鎖的三種方式,不過說實話,mysql的性能確實在高并發(fā)環(huán)境下,不值得期待,但是多了解下這種知識,也算是擴(kuò)寬下自己的解決問題的思路吧。
共勉
總結(jié)
以上是生活随笔為你收集整理的mysql分布式安装可靠读写案列图解,高并发下的分布式锁-mysql篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab高级图形设计实训上机答案,M
- 下一篇: es ik分词热更新MySQL,Elas