亚洲精品中文字幕无码专区一,中文字幕av一区乱码深夜动态福利,粗大的内捧猛烈进出少妇

          系統城裝機大師 - 固鎮縣祥瑞電腦科技銷售部宣傳站!

          當前位置:首頁 > 數據庫 > Mysql > 詳細頁面

          MySQL樂觀鎖和悲觀鎖具體實現

          時間:2022-09-11來源:www.snowmanhill.com作者:電腦系統城

          于MySQL中的樂觀鎖和悲觀鎖,可能很多的開發者還不是很熟悉,并不知道其中具體是如何實現的。本文就針對這個問題做一個實際案例演示,讓你徹底明白這兩種鎖的區別。

          鎖分類

          MySQL的中鎖按照范圍主要分為表鎖、行鎖和頁面鎖。其中myisam存儲引擎只支持表鎖,InnoDB不僅僅支持行鎖,在一定程度上也支持表鎖。按照行為可以分為共享鎖(讀鎖)、排他鎖(寫鎖)和意向鎖。按照思想分為樂觀鎖和悲觀鎖。

          今天的文章演示一下實際中的樂觀鎖和悲觀鎖是如何操作的。

          表結構

          下面的SQL語句是表的結構:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          CREATE TABLE `demo`.`user` (
          `id` int(10) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
          `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
          `sex` tinyint(1) UNSIGNED NOT NULL DEFAULT 0,
          `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
          `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
          `version` int(1) NULL DEFAULT 1 COMMENT '數據版本號',
          PRIMARY KEY (`id`) USING BTREE
          ) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

          插入模擬數據:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          BEGIN;
          INSERT INTO `user` VALUES (0000000001, '張三', 0, '18228937997@163.com', '18228937997', 1);
          INSERT INTO `user` VALUES (0000000002, '李四', 0, '1005349393@163.com', '15683202302', 1);
          INSERT INTO `user` VALUES (0000000003, '李四1', 0, '1005349393@163.com', '15683202302', 1);
          INSERT INTO `user` VALUES (0000000004, '李四2', 0, '1005349393@163.com', '15683202302', 1);
          INSERT INTO `user` VALUES (0000000005, '李四3', 0, '1005349393@163.com', '15683202302', 1);
          INSERT INTO `user` VALUES (0000000006, '李四4', 0, '1005349393@163.com', '15683202302', 1);
          INSERT INTO `user` VALUES (0000000007, '李四55', 0, '1005349393@163.com', '15683202302', 1);
          COMMIT;

          表中數據。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          mysql root@127.0.0.1:demo> select * from user;
          +----+--------+-----+---------------------+-------------+---------+
          | id | name | sex | email | mobile | version |
          +----+--------+-----+---------------------+-------------+---------+
          | 1 | 張三 | 0 | 18228937997@163.com | 18228937997 | 2 |
          | 2 | 李四 | 0 | 1005349393@163.com | 15683202302 | 1 |
          | 3 | 李四1 | 0 | 1005349393@163.com | 15683202302 | 1 |
          | 4 | 李四2 | 0 | 1005349393@163.com | 15683202302 | 1 |
          | 5 | 李四3 | 0 | 1005349393@163.com | 15683202302 | 1 |
          | 6 | 李四4 | 0 | 1005349393@163.com | 15683202302 | 1 |
          | 7 | 李四55 | 0 | 1005349393@163.com | 15683202302 | 1 |
          +----+--------+-----+---------------------+-------------+---------+
          7 rows in set
          Time: 0.011s

          悲觀鎖

          悲觀鎖,比較消極的一種鎖處理方式。直接在操作數據時,搶占鎖。其他的事務在進行時就會等待,直到占有鎖的事務釋放鎖為止。

          這種處理方式能保證數據的最大一致性,但是容易導致鎖超時、并發程度低等問題。 首先我們開啟事務一,并且對id=1的數據進行update操作,此時我們不提交事務。

          1
          2
          3
          4
          5
          6
          mysql root@127.0.0.1:demo> begin;
          Query OK, 0 rows affected
          Time: 0.002s
          mysql root@127.0.0.1:demo> update `user` set name = '張三111111'where id = 1;
          Query OK, 1 row affected
          Time: 0.004s

          接著我們開啟事務二,對id=1的數據進行update操作,查看此時會發生什么情況?

          1
          2
          3
          4
          mysql root@127.0.0.1:demo> begin;
          Query OK, 0 rows affected
          Time: 0.002s
          mysql root@127.0.0.1:demo> update `user` set sex = 1 where id = 1;

          我們執行完update語句之后,就處于等待狀態,SQL語句也不會馬上被執行,這是因為事務一沒有commit,也就沒有釋放id=1的數據對應的寫鎖。

          效果如下圖:

          通過上面的例子,我們就能比較直觀的感受到悲觀鎖的實現過程是如何的。

          樂觀鎖

          樂觀鎖認為數據一般情況下不會造成沖突,只有當數據去執行修改情況時,才會針對數據沖突做處理。這里是如何發現沖突了呢?常規的方式,都是在數據行上加一個版本號或者時間戳等字段。(本文使用version作為版本好方式,使用時間戳方式同理)

          樂觀鎖的實現原理:

          • 一個事務在讀取數據時,將對應的版本號字段讀取出來,假設此時的版本號是1。
          • 另外一個事務也是執行同樣的讀取操作。當事務一提交時,對版本號執行+1,此時該數據行的版本號就是2。
          • 第二個事務執行修改操作時,針對業務數據做條件,并默認增加一個版本號作為where條件。此時修改語句中的版本號字段是不滿足where條件,該事務執行失敗。通過這種方式來達到鎖的功能。

          客戶端一:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          mysql root@127.0.0.1:demo> select * from user where id = 1;
          +----+------------+-----+---------------------+-------------+---------+
          | id | name | sex | email | mobile | version |
          +----+------------+-----+---------------------+-------------+---------+
          | 1 | 張三111111 | 0 | 18228937997@163.com | 18228937997 | 1 |
          +----+------------+-----+---------------------+-------------+---------+
          1 row in set
          Time: 0.012s
          mysql root@127.0.0.1:demo> update `user` set name = '事務一', version = version + 1 where id = 1 and version = 1;
          Query OK, 1 row affected
          Time: 0.008s
          mysql root@127.0.0.1:demo> select * from user where id = 1;
          +----+--------+-----+---------------------+-------------+---------+
          | id | name | sex | email | mobile | version |
          +----+--------+-----+---------------------+-------------+---------+
          | 1 | 事務一 | 1 | 18228937997@163.com | 18228937997 | 2 |
          +----+--------+-----+---------------------+-------------+---------+
          1 row in set
          Time: 0.009s

          執行update語句的順序應該在客戶端二執行了select之后,在執行。

          客戶端二:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          mysql root@127.0.0.1:demo> select * from user where id = 1;
          +----+------------+-----+---------------------+-------------+---------+
          | id | name | sex | email | mobile | version |
          +----+------------+-----+---------------------+-------------+---------+
          | 1 | 張三111111 | 1 | 18228937997@163.com | 18228937997 | 1 |
          +----+------------+-----+---------------------+-------------+---------+
          1 row in set
          Time: 0.015s
          mysql root@127.0.0.1:demo> update `user` set name = '事務二', version = version + 1 where id = 1 and version = 1;
          Query OK, 0 rows affected
          Time: 0.003s
          mysql root@127.0.0.1:demo> select * from user where id = 1;
          +----+--------+-----+---------------------+-------------+---------+
          | id | name | sex | email | mobile | version |
          +----+--------+-----+---------------------+-------------+---------+
          | 1 | 事務一 | 1 | 18228937997@163.com | 18228937997 | 2 |
          +----+--------+-----+---------------------+-------------+---------+
          1 row in set
          Time: 0.012s

          此時根據update返回的結構,可以看出受影響的行數為0,同時select查詢之后,返現數據也是事務一的數據。

          適用場景

          悲觀鎖:比較適合寫入操作比較頻繁的場景,如果出現大量的讀取操作,每次讀取的時候都會進行加鎖,這樣會增加大量的鎖的開銷,降低了系統的吞吐量。

          樂觀鎖:比較適合讀取操作比較頻繁的場景,如果出現大量的寫入操作,數據發生沖突的可能性就會增大,為了保證數據的一致性,應用層需要不斷的重新獲取數據,這樣會增加大量的查詢操作,降低了系統的吞吐量。

          總結

          兩種所各有優缺點,讀取頻繁使用樂觀鎖,寫入頻繁使用悲觀鎖。

          像樂觀鎖適用于寫比較少的情況下,即沖突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果經常產生沖突,上層應用會不斷的進行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適,之所以用悲觀鎖就是因為兩個用戶更新同一條數據的概率高,也就是沖突比較嚴重的情況下,所以才用悲觀鎖。

          分享到:

          相關信息

          系統教程欄目

          欄目熱門教程

          人氣教程排行

          站長推薦

          熱門系統下載

          亚洲精品中文字幕无码专区一,中文字幕av一区乱码深夜动态福利,粗大的内捧猛烈进出少妇