<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
工欲善其事必先利其器,在基於MySQL實現分散式鎖之前,我們要先了解一點MySQL鎖自身的相關內容
我們知道:鎖是計算機協調多個程序或者執行緒並行存取同一資源的機制,而在資料庫中,除了傳統的機器資源的爭用之外,儲存下來的資料也屬於供使用者共用的資源,所以如何保證資料並行的一致性,有效性是每個資料庫必須解決的問題。
除此之外,鎖衝突也是影響資料庫並行效能的主要因素,所以鎖對於資料庫而言就顯得非常重要,也非常複雜。
而儲存引擎是MySQL中非常重要的底層元件,主要用來處理不同型別的SQL操作,其中包括建立,讀取,刪除和修改操作。在MySQL中提供了不同型別的儲存引擎,根據其不同的特性提供了不同的儲存機制,索引和鎖功能。
根據show engines;
能夠列出MySQL下支援的儲存引擎
如果沒有特殊指定,那麼在MySQL8.0
中會設定InnoDB
為預設的儲存引擎
在實際工作中,根據需求選擇最多的兩種儲存引擎分別為:
所以我們主要針對這兩種型別來介紹MySQL的鎖
InnoDB
支援多粒度鎖定,可以支援行鎖,也可以支援表鎖。如果沒有升級鎖粒度,那麼預設情況下是以行鎖來設計的。
關於行鎖和表鎖的介紹:
這裡沒法說明那種鎖最好,只有合適不合適
在行級鎖中,可以分為兩種型別
共用鎖又稱為讀鎖,允許其他事務讀取被鎖定的物件,也可以在其上獲取其他共用鎖,但不能寫入。
舉個例子:
下面是關於共用鎖的具體實現,關鍵程式碼:select .. from table lock in share mode
-- 建立範例表 create table tb_lock( id bigint primary key auto_increment, t_name varchar(20) ) engine=InnoDB;
開啟兩個視窗來測試:
session1 | session2 |
---|---|
set autocommit=0; | set autocommit=0; |
select * from tb_lock where t_name = ‘zs’ lock in share mode; | |
select * from tb_lock where t_name = ‘zs’ lock in share mode; | |
select * from tb_lock where t_name = ‘lsp’ lock in share mode; | |
update tb_lock set t_name = ‘lzs’ where t_name = ‘zs’; | |
update tb_lock set t_name = ‘lsp111’ where t_name = ‘lsp’; | |
select * from tb_lock where t_name = ‘zs’; | |
commit; |
自動提交全部關閉,可以通過
select @@autocommit;
來檢視
通過以上實驗,我們總結:
修改,刪除,插入會預設對涉及到的資料加上排他鎖
select
操作不會有任何影響,select
不會加任何鎖commit;
自動釋放鎖又叫寫鎖。只允許獲取鎖的事務對資料進行操作【更新,刪除】,其他事務對相同資料集只能進行讀取,不能有跟新或者刪除操作。而且也不能在相同資料集獲取到共用鎖。
沒錯,就是這麼霸道
在MySQL中,想要基於排它鎖實現行級鎖,就需要對錶中索引列加鎖,否則的話,排它鎖就屬於表級鎖
下面一一來展示,關鍵程式碼:select .. from XX for update
首先是有索引列狀態
session1 | session2 |
---|---|
set autocommit=0; | set autocommit=0; |
select * from tb_lock; | select * from tb_lock; |
select * from tb_lock where id = 1 for update; | |
select * from tb_lock where id = 1 for update; | |
select * from tb_lock where id = 2 for update; | |
commit; |
通過以上實驗,得到結論:
Lock wait timeout exceeded; try restarting transaction
下面是無索引列狀態
session1 | session2 |
---|---|
set autocommit=0; | set autocommit=0; |
select * from tb_lock; | select * from tb_lock; |
select * from tb_lock where t_name = ‘ls’ for update; | |
select * from tb_lock where t_name = ‘ls’ for update; | |
commit |
通過以上實驗,得到結論:
接下來我們來看看MyISAM的方式
MyISAM屬於表級鎖,被用來防止任何其他事務存取表的鎖。
其中表鎖又分為兩種形式
這裡我們要注意:表級鎖只能防止其他對談進行不適當的讀取或寫入。
- 持有
WRITE
鎖的對談可以執行表級操作,比如DELETE
或者TRUNCATE
- 持有對談
READ
鎖,不能夠執行DELETE
或者TRUNCATE
操作
不管是READ
還是WRITE
,都是通過lock table
來獲取表鎖的,而READ
鎖擁有如下特性:
READ
表的鎖,而其他對談可以在不顯式獲取READ
鎖的情況下讀取該表:也就是說直接通過select
來操作那麼,接下來我們來看實際操作,關鍵程式碼:lock tables table_name read
create table tb_lock_isam( id bigint primary key auto_increment, t_name varchar(20) ) engine=MyISAM;
開啟兩個視窗來進行操作:
session1 | session2 |
---|---|
set autocommit=0; | set autocommit=0; |
LOCK TABLES tb_lock_isam READ; | |
select * from tb_lock_isam; | |
select * from tb_lock; | |
select * from tb_lock_isam; | |
LOCK TABLES tb_lock_isam READ; | |
select * from tb_lock_isam; | |
select * from tb_lock; | |
unlock tables; | insert into tb_lock_isam(t_name) values(‘ll’); |
通過以上實戰,驗證以下結論:
Table 'tb_lock' was not locked with LOCK TABLES
Table 'tb_lock_isam' was locked with a READ lock and can't be updated
WRITE鎖
的特性和排它鎖
的特性非常相似,都特別霸道:
WRITE
持有鎖時被阻塞還是通過具體實戰來進行演示效果,關鍵程式碼:lock tables table_name write
session1 | session2 |
---|---|
select * from tb_lock_isam; | select * from tb_lock_isam; |
lock table tb_lock_isam write; | |
select * from tb_lock_isam; | |
insert into tb_lock_isam(t_name) values(‘66’); | |
select * from tb_lock_isam; | |
unlock tables; |
通過以上實戰,驗證以下結論:
WRITE鎖
的時候,在當前事務下可以對獲取鎖的表進行任何操作,其他事務無法對錶進行任意操作。WRITE鎖
之後,只能在當前事務下操作獲取鎖的表,無法操作其他表,否則會出現以下異常Table 'tb_index' was not locked with LOCK TABLES'
【注意】
MyISAM
在執行查詢語句之前,會自動給涉及的所有表加讀鎖,在執行更新操作前,會自動給涉及的表加寫鎖,這個過程並不需要使用者干預,因此使用者一般不需要使用命令來顯式加鎖
既然已經瞭解到了MySQL鎖相關內容,那麼我們就來看看如何實現,首先我們需要建立一張資料表
當然,只需要初始化建立一次
create table if not exists fud_distribute_lock( id bigint unsigned primary key auto_increment, biz varchar(50) comment '業務Key' unique(biz) ) engine=innodb;
在其中,biz
是為了區分不同的業務,也可以理解為資源隔離,並且對biz
設定唯一索引,也能夠防止其鎖級別變為表級鎖
既然for udpate
就是加鎖成功,事務提交就自動釋放鎖,那麼這個事情就非常好辦了:
// 省略了構造方法,需要傳入DataSource和biz private static final String SELECT_SQL = "SELECT * FROM fud_distribute_lock WHERE `biz` = ? for update"; private static final String INSERT_SQL = "INSERT INTO fud_distribute_lock(`biz`) values(?)"; // 從構造方法中傳入 private final DataSource source; private Connection connection; public void lock() { PreparedStatement psmt = null; ResultSet rs = null; try { // while(true); for (; ; ) { connection = this.source.getConnection(); // 關閉自動提交事務 connection.setAutoCommit(false); psmt = connection.prepareStatement(SELECT_SQL); psmt.setString(1, biz); rs = psmt.executeQuery(); if (rs.next()) { return; } connection.commit(); close(connection, psmt, rs); // 如果沒有相關查詢,需要插入 Connection updConnection = this.source.getConnection(); PreparedStatement insertStatement = null; try { insertStatement = updConnection.prepareStatement(INSERT_SQL); insertStatement.setString(1, biz); if (insertStatement.executeUpdate() == 1) { LOGGER.info("建立鎖記錄成功"); } } catch (Exception e) { LOGGER.error("建立鎖記錄異常:{}", e.getMessage()); } finally { close(insertStatement, updConnection); } } } catch (Exception e) { LOGGER.error("lock異常資訊:{}", e.getMessage()); throw new BusException(e); } finally { close(psmt, rs); } } public void unlock() { try { // 事務提交之後自動解鎖 connection.commit(); close(connection); } catch (Exception e) { LOGGER.error("unlock異常資訊:{}", e.getMessage()); throw new BusException(e); } } public void close(AutoCloseable... closeables) { Arrays.stream(closeables).forEach(closeable -> { if (null != closeable) { try { closeable.close(); } catch (Exception e) { LOGGER.error("close關閉異常:{}", e.getMessage()); } } }); }
如果一個請求是第一次進來的,比如biz=order
,在這個表中是不會儲存order
這條記錄,那麼select ...for update
就不會生效,所以就需要先將order
插入到表記錄中,也就是執行insert
操作。
insert
執行成功之後,記錄select...for update
,這樣獲取鎖才能生效
基於MySQL的分散式鎖在實際開發過程中很少使用,但是我們還是要有一個思路在。那麼本節針對MySQL的分散式鎖實現到這裡就結束了,掌握了MySQL的基礎鎖,那麼就會非常簡單了。
到此這篇關於MySQL實現分散式鎖的文章就介紹到這了,更多相關MySQL分散式鎖內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45