成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

mysql居然還能實現分布式鎖的方法

瀏覽:5日期:2023-10-07 09:06:22
前言

之前的文章中通過電商場景中秒殺的例子和大家分享了單體架構中鎖的使用方式,但是現在很多應用系統都是相當龐大的,很多應用系統都是微服務的架構體系,那么在這種跨jvm的場景下,我們又該如何去解決并發。

單體應用鎖的局限性

在進入實戰之前簡單和大家粗略聊一下互聯網系統中的架構演進。

mysql居然還能實現分布式鎖的方法

在互聯網系統發展之初,消耗資源比較小,用戶量也比較小,我們只部署一個tomcat應用就可以滿足需求。一個tomcat我們可以看做是一個jvm的進程,當大量的請求并發到達系統時,所有的請求都落在這唯一的一個tomcat上,如果某些請求方法是需要加鎖的,比如上篇文章中提及的秒殺扣減庫存的場景,是可以滿足需求的。但是隨著訪問量的增加,一個tomcat難以支撐,這時候我們就需要集群部署tomcat,使用多個tomcat支撐起系統。

在上圖中簡單演化之后,我們部署兩個Tomcat共同支撐系統。當一個請求到達系統的時候,首先會經過nginx,由nginx作為負載均衡,它會根據自己的負載均衡配置策略將請求轉發到其中的一個tomcat上。當大量的請求并發訪問的時候,兩個tomcat共同承擔所有的訪問量。這之后我們同樣進行秒殺扣減庫存的時候,使用單體應用鎖,還能滿足需求么?

之前我們所加的鎖是JDK提供的鎖,這種鎖在單個jvm下起作用,當存在兩個或者多個的時候,大量并發請求分散到不同tomcat,在每個tomcat中都可以防止并發的產生,但是多個tomcat之間,每個Tomcat中獲得鎖這個請求,又產生了并發。從而扣減庫存的問題依舊存在。這就是單體應用鎖的局限性。那我們如果解決這個問題呢?接下來就要和大家分享分布式鎖了。

分布式鎖什么是分布式鎖?

那么什么是分布式鎖呢,在說分布式鎖之前我們看到單體應用鎖的特點就是在一個jvm進行有效,但是無法跨越jvm以及進程。所以我們就可以下一個不那么官方的定義,分布式鎖就是可以跨越多個jvm,跨越多個進程的鎖,像這樣的鎖就是分布式鎖。

設計思路

mysql居然還能實現分布式鎖的方法

由于tomcat是java啟動的,所以每個tomcat可以看成一個jvm,jvm內部的鎖無法跨越多個進程。所以我們實現分布式鎖,只能在這些jvm外去尋找,通過其他的組件來實現分布式鎖。

上圖兩個tomcat通過第三方的組件實現跨jvm,跨進程的分布式鎖。這就是分布式鎖的解決思路。

實現方式

那么目前有哪些第三方組件來實現呢?目前比較流行的有以下幾種:

數據庫,通過數據庫可以實現分布式鎖,但是高并發的情況下對數據庫的壓力比較大,所以很少使用。 Redis,借助redis可以實現分布式鎖,而且redis的java客戶端種類很多,所以使用方法也不盡相同。 Zookeeper,也可以實現分布式鎖,同樣zk也有很多java客戶端,使用方法也不同。

針對上述實現方式,老貓還是通過具體的代碼例子來一一演示。

基于數據庫的分布式鎖

思路:基于數據庫悲觀鎖去實現分布式鎖,用的主要是select ... for update。select ... for update是為了在查詢的時候就對查詢到的數據進行了加鎖處理。當用戶進行這種行為操作的時候,其他線程是禁止對這些數據進行修改或者刪除操作,必須等待上個線程操作完畢釋放之后才能進行操作,從而達到了鎖的效果。

實現:我們還是基于電商中超賣的例子和大家分享代碼。

咱們還是利用上次單體架構中的超賣的例子和大家分享,針對上次的代碼進行改造,我們新鍵一張表,叫做distribute_lock,這張表的目的主要是為了提供數據庫鎖,我們來看一下這張表的情況。

mysql居然還能實現分布式鎖的方法

由于我們這邊模擬的是訂單超賣的場景,所以在上圖中我們有一條訂單的鎖數據。

我們將上一篇中的代碼改造一下抽取出一個controller然后通過postman去請求調用,當然后臺是啟動兩個jvm進行操作,分別是8080端口以及8081端口。完成之后的代碼如下:

/** * @author kdaddy@163.com * @date 2021/1/3 10:48 * @desc 公眾號“程序員老貓” */@Service@Slf4jpublic class MySQLOrderService { @Resource private KdOrderMapper orderMapper; @Resource private KdOrderItemMapper orderItemMapper; @Resource private KdProductMapper productMapper; @Resource private DistributeLockMapper distributeLockMapper; //購買商品id private int purchaseProductId = 100100; //購買商品數量 private int purchaseProductNum = 1; @Transactional(propagation = Propagation.REQUIRED) public Integer createOrder() throws Exception{ log.info('進入了方法'); DistributeLock lock = distributeLockMapper.selectDistributeLock('order'); if(lock == null) throw new Exception('該業務分布式鎖未配置'); log.info('拿到了鎖'); //此處為了手動演示并發,所以我們暫時在這里休眠1分鐘 Thread.sleep(60000); KdProduct product = productMapper.selectByPrimaryKey(purchaseProductId); if (product==null){ throw new Exception('購買商品:'+purchaseProductId+'不存在'); } //商品當前庫存 Integer currentCount = product.getCount(); log.info(Thread.currentThread().getName()+'庫存數'+currentCount); //校驗庫存 if (purchaseProductNum > currentCount){ throw new Exception('商品'+purchaseProductId+'僅剩'+currentCount+'件,無法購買'); } //在數據庫中完成減量操作 productMapper.updateProductCount(purchaseProductNum,'kd',new Date(),product.getId()); //生成訂單 ...次數省略,源代碼可以到老貓的github下載:https://github.com/maoba/kd-distribute return order.getId(); }}

SQL的寫法如下:

select * from distribute_lock where business_code = #{business_code,jdbcType=VARCHAR} for update

以上為主要實現邏輯,關于代碼中的注意點:

createOrder方法必須要有事務,因為只有在事務存在的情況下才能觸發select for update的鎖。 代碼中必須要對當前鎖的存在性進行判斷,如果為空的情況下,會報異常

我們來看一下最終運行的效果,先看一下console日志,

8080的console日志情況:

11:49:41 INFO 16360 --- [nio-8080-exec-2] c.k.d.service.MySQLOrderService : 進入了方法11:49:41 INFO 16360 --- [nio-8080-exec-2] c.k.d.service.MySQLOrderService : 拿到了鎖

8081的console日志情況:

11:49:48 INFO 17640 --- [nio-8081-exec-2] c.k.d.service.MySQLOrderService : 進入了方法

通過日志情況,兩個不同的jvm,由于第一個到8080的請求優先拿到了鎖,所以8081的請求就處于等待鎖釋放才會去執行,這說明我們的分布式鎖生效了。再看一下完整執行之后的日志情況:

8080的請求:

11:58:01 INFO 15380 --- [nio-8080-exec-1] c.k.d.service.MySQLOrderService : 進入了方法11:58:01 INFO 15380 --- [nio-8080-exec-1] c.k.d.service.MySQLOrderService : 拿到了鎖11:58:07 INFO 15380 --- [nio-8080-exec-1] c.k.d.service.MySQLOrderService : http-nio-8080-exec-1庫存數1

8081的請求:

11:58:03 INFO 16276 --- [nio-8081-exec-1] c.k.d.service.MySQLOrderService : 進入了方法11:58:08 INFO 16276 --- [nio-8081-exec-1] c.k.d.service.MySQLOrderService : 拿到了鎖11:58:14 INFO 16276 --- [nio-8081-exec-1] c.k.d.service.MySQLOrderService : http-nio-8081-exec-1庫存數011:58:14 ERROR 16276 --- [nio-8081-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.Exception: 商品100100僅剩0件,無法購買] with root cause

java.lang.Exception: 商品100100僅剩0件,無法購買 at com.kd.distribute.service.MySQLOrderService.createOrder(MySQLOrderService.java:61) ~[classes/:na]

很明顯第二個請求由于沒有庫存,導致最終購買失敗的情況,當然這個場景也是符合我們正常的業務場景的。最終我們數據庫的情況是這樣的:

mysql居然還能實現分布式鎖的方法

mysql居然還能實現分布式鎖的方法

很明顯,我們到此數據庫的庫存和訂單數量也都正確了。到此我們基于數據庫的分布式鎖實戰演示完成,下面我們來歸納一下如果使用這種鎖,有哪些優點以及缺點。

優點:簡單方便、易于理解、易于操作。 缺點:并發量大的時候對數據庫的壓力會比較大。 建議:作為鎖的數據庫和業務數據庫分開。寫在最后

對于上述數據庫分布式鎖,其實在我們的日常開發中用的也是比較少的。基于redis以及zk的鎖倒是用的比較多一些,本來老貓想把redis鎖以及zk鎖放在這一篇中一起分享掉,但是再寫在同一篇上面的話,篇幅就顯得過長了,因此本篇就和大家分享這一種分布式鎖。源碼大家可以在老貓的github中下載到。地址是:https://github.com/maoba/kd-distribute

到此這篇關于mysql居然還能實現分布式鎖的方法的文章就介紹到這了,更多相關mysql 分布式鎖內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: MySQL 數據庫
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
日韩精品欧美精品| 欧美成人69av| 成人午夜精品一区二区三区| 成人免费视频一区| 国产精品日韩高清| 欧美亚州在线观看| 久久精品人人做人人爽97| 岛国精品在线观看| 3d成人动漫网站| 久久99国内精品| 欧美色综合网站| 久久er99精品| 欧美撒尿777hd撒尿| 美女精品自拍一二三四| 在线观看日韩av先锋影音电影院| 三级欧美在线一区| 一本大道综合伊人精品热热 | 日韩欧美精品三级| 国产一区二区免费在线| 欧美三级视频在线观看| 麻豆精品视频在线观看| 日韩高清在线电影| 日本韩国欧美一区二区三区| 亚洲成人福利片| 国产一区二区三区四区五区美女 | 欧美在线色视频| 免费精品视频在线| 色狠狠色狠狠综合| 伦理电影国产精品| 69堂成人精品免费视频| 成人在线一区二区三区| 精品乱码亚洲一区二区不卡| 97成人超碰视| 国产精品视频yy9299一区| 国产精品分类| 一区二区免费在线| 母乳一区在线观看| 麻豆专区一区二区三区四区五区| 精品视频一区 二区 三区| 激情深爱一区二区| 欧美电影免费观看高清完整版在线 | 激情文学综合丁香| 精品三级av在线| 欧美日韩精品免费观看| 成人欧美一区二区三区小说 | 久久九九久精品国产免费直播| 欧美久久久久久| 亚洲欧美一区二区三区久本道91| 9久re热视频在线精品| 亚洲第一二三四区| 欧美伦理视频网站| 91免费版在线| 一区二区三区在线视频免费观看| 91福利小视频| 国产iv一区二区三区| 国产亚洲精品超碰| 亚洲精品一区二区三区樱花| 亚洲韩国精品一区| 欧美揉bbbbb揉bbbbb| 高清不卡一二三区| 一区视频在线播放| 在线观看亚洲一区| 成人精品电影在线观看| 国产精品美女久久福利网站| 亚洲一区中文| 久久97超碰色| 欧美精品一区二区在线播放| 在线精品一区| 美女一区二区三区| 2021久久国产精品不只是精品| 极品av少妇一区二区| 免费在线观看不卡| 久久夜色精品国产噜噜av| 亚洲精选久久| 毛片av中文字幕一区二区| 久久久一区二区三区| 一区二区三区三区在线| 久久电影网电视剧免费观看| 久久久91精品国产一区二区精品 | 亚洲一区二三区| 欧美精品 日韩| 国产精品av久久久久久麻豆网| 图片区小说区国产精品视频| 精品久久久久99| 国产精品毛片在线看| 国产在线播精品第三| 亚洲三级久久久| 欧美日韩成人在线| 极品中文字幕一区| 国产呦萝稀缺另类资源| 亚洲婷婷国产精品电影人久久| 欧美日韩国产高清一区二区三区| 欧美视频在线观看| 青青草精品视频| 中文字幕不卡在线| 欧美性猛交一区二区三区精品| 欧美福利电影在线观看| 欧美a级一区二区| 国产拍揄自揄精品视频麻豆| 91传媒视频在线播放| 91麻豆高清视频| 日本不卡中文字幕| 国产农村妇女毛片精品久久麻豆| 久久一日本道色综合久久| 色综合久久综合| 天堂久久一区二区三区| 久久精品人人做人人综合| 欧美在线小视频| 亚洲高清电影| 成人av午夜电影| 日韩av在线播放中文字幕| 国产亚洲婷婷免费| 欧美日韩日日夜夜| 亚洲国产成人不卡| 成人少妇影院yyyy| 热久久免费视频| 亚洲欧美激情小说另类| 日韩午夜激情视频| 久热这里只精品99re8久| 国产精品yjizz| 国产激情一区二区三区桃花岛亚洲| 一区二区三区美女| 国产亚洲一区二区在线观看| 欧美三级中文字幕| 国产农村妇女毛片精品久久莱园子 | 亚洲视频你懂的| 日韩精品影音先锋| 在线观看视频91| 国产日韩精品久久| 欧美视频在线观看| av成人老司机| 国产精品一区二区在线播放| 亚洲va欧美va人人爽午夜 | 国产在线日韩欧美| 婷婷中文字幕一区三区| 国产精品成人网| 久久综合色鬼综合色| 欧美色成人综合| 久久裸体视频| 激情久久久久久| 欧美在线3区| 成人午夜在线播放| 久久99精品久久久久久久久久久久| 伊人性伊人情综合网| 欧美激情一区不卡| 精品国产制服丝袜高跟| 欧美日韩另类一区| 色美美综合视频| 国产精品免费看| 狠久久av成人天堂| 你懂的国产精品| 成人激情视频网站| 国产精品 欧美精品| 经典三级视频一区| 日本在线观看不卡视频| 亚洲影院免费观看| 亚洲男人电影天堂| 中文字幕在线不卡一区| 国产三级欧美三级日产三级99 | 亚洲不卡av一区二区三区| 一区二区三区免费看视频| 综合在线观看色| 国产精品视频在线看| 国产精品入口麻豆九色| 国产视频亚洲色图| 久久久久国产精品麻豆| wwww国产精品欧美| 久久午夜羞羞影院免费观看| 精品日韩一区二区| 亚洲精品一区二区精华| 精品免费视频.| 精品国产精品一区二区夜夜嗨 | 亚洲二区在线视频| 亚洲美女免费在线| 国产精品成人在线观看| 国产精品国产自产拍高清av王其| 国产精品视频一区二区三区不卡| 国产欧美日产一区| 国产精品热久久久久夜色精品三区| 26uuu国产电影一区二区| 精品国产乱码91久久久久久网站| 精品国产一区二区三区av性色| 精品日韩欧美在线| 精品国产三级电影在线观看| 欧美mv日韩mv亚洲| 久久精品视频在线免费观看| 国产精品色哟哟| 一区二区三区在线视频播放| 亚洲成人av一区二区| 天堂一区二区在线| 久久草av在线| 国产99久久久久久免费看农村| 成人网页在线观看| 欧美黄色免费| 激情亚洲网站| 午夜亚洲伦理| 在线观看91精品国产入口| 69堂成人精品免费视频| 精品国产91乱码一区二区三区 | 性欧美大战久久久久久久久|