Mysql 樂觀鎖 和悲觀鎖

2022-09-13 01:51:12 字數 2488 閱讀 3203

平時看部落格或技術文章的時候,經常被各種鎖搞得暈暈乎乎,包括在 自旋鎖、可重入鎖、公平鎖等等 、樂觀鎖、悲觀鎖、行鎖、表鎖、意向鎖、排它鎖等。前段時間終於把j**a多執行緒相關的鎖有機會學習了一遍。現在開始整理mysql相關的鎖概念。先從樂觀鎖和悲觀鎖開始聊聊。

首先要知道,樂觀鎖和悲觀鎖不是真實存在的鎖,只是兩種抽象概念性的東西,就相當於j**a中的介面,只是給出了乙個定義,一種思想。可以根據這種思想去實現。

悲觀鎖是資料庫層面實現的鎖機制,他是指對於其他執行緒對本資料的修改是持有保守態度。在對資料操作前,首先要獲取鎖, 保證其他在修改期間,其他執行緒對資料不能進行修改。

j**a 中的synsynchronized 就是悲觀鎖思想的一種體現。

mysql中,悲觀鎖的實現方式是:使用語句 select *  ...... forupdate  鎖住當前行資料。

如果能正確獲取鎖,那麼其他執行緒要對於這條資料做修改,必須等待這個事務提交釋放鎖之後,才會執行。

下面舉個栗子:

建立一張表,並開兩個查詢視窗。都關閉自動提交。

建表語句:

drop table if exists `lock_demo`;

create table `lock_demo` (

`id` bigint(20) not null auto_increment,

`count`

int(11) default null,

`version`

int(255) default null,

primary key (`id`)

) engine=innodb auto_increment=2 default charset=utf8mb4;

insert into `lock_demo` values ('1', '1', '0');

視窗1,加鎖

//

查詢視窗1

set autocommit = 0;

select * from lock_demo where id = 1 for update;

視窗2 ,關閉自動提交,進行資料查詢,可以查詢出資料,表明悲觀鎖對於其他執行緒資料查詢是不受影響的

set autocommit = 0; 

select * from lock_demo where id = 1

當視窗 2 進行加鎖或更新的時候,那麼就會報錯,因為一直獲取不到鎖,就會提示超時。

//另乙個執行緒進行加鎖

select * from lock_demo where id = 1 for

update;

//另乙個執行緒更新

update lock_demo set version = 2 where id = 1;

錯誤提示資訊:

[err] 1205 - lock wait timeout exceeded; try restarting transaction

當前執行緒提交事務後,其他執行緒才能進行更新。

這裡引出了悲觀鎖涉及到的另外兩個鎖概念,它們就是共享鎖與排它鎖。

共享鎖和排它鎖是悲觀鎖的不同的實現,它倆都屬於悲觀鎖的範疇。

語法: 

select * from table lock in share mode

語法:

select * from table for update

innodb 儲存在執行修改、刪除的時候,都是會預設增加排它鎖。

在查詢的時候,是不加任何鎖的,注意不是加了共享鎖,是不加任何鎖的。所以才會有在第乙個事務中加排它鎖的時候,第二個事物依舊可以通過 select * ...... 的方式查詢。

但是不能再加鎖,共享鎖和排它鎖都不行,也就是執行    select * from table for update      select * from table lock in share mode  都不行,也就是執行update 和delete 操作都是不行的。

那麼插入資料是是否受影響呢,答案是肯定不受影響。

首先,共享鎖和排它鎖的粒度是行,也就是針對一行資料。例如你再id = 1的資料上加了排他鎖,那麼id = 2的資料依舊可以更新刪除,更不用說去新增一條資料了。

樂觀鎖表示對資料的更新持有樂觀態度,表示不會造成衝突,所以一般是先進行業務處理,在對資料更新的時候再去判定是否有衝突。

樂觀鎖是使用者自己實現的,不是資料庫層面的鎖。

原理就是:

在表字段中加乙個version 字段。每次更新的時候去檢查當前查詢的資料中的version 與資料庫中的version是否相同,如果不同則不進行更新,相同則進行更新,然後將version 加1

類似的可以使時間戳實現相同的功能。

悲觀鎖是資料庫級別實現的,直接使用 select * .....  for update 就表示對當前資料加鎖。

樂觀鎖是需要自己實現,一般是通過版本控制或者加時間戳等方式實現。

參考文章:

MySQL 樂觀鎖和悲觀鎖

共享鎖 s鎖 又稱讀鎖,若事務t對資料物件a加上s鎖,則事務t可以讀a但不能修改a,其他事務只能再對a加s鎖,而不能加x鎖,直到t釋放a上的s鎖。這保證了其他事務可以讀a,但在t釋放a上的s鎖之前不能對a做任何修改。排他鎖 x鎖 又稱寫鎖。若事務t對資料物件a加上x鎖,事務t可以讀a也可以修改a,其...

Mysql 樂觀鎖和悲觀鎖

假定每次操作都不會產生衝突,一般使用cas進行解決。update set num num 1 where num and name 假定每次操作都會衝突,都需要加鎖解決。select for update 結果集中的任何行資料使用排他鎖或共享鎖,否則申請會阻塞for update僅適用於innodb...

mysql 樂觀鎖和悲觀鎖

悲觀鎖與樂觀鎖是兩種常見的資源併發鎖設計思路,也是併發程式設計中乙個非常基礎的概念。本文將對這兩種常見的鎖機制在資料庫資料上的實現進行比較系統的介紹。悲觀鎖 pessimistic lock 悲觀鎖的特點是先獲取鎖,再進行業務操作,即 悲觀 的認為獲取鎖是非常有可能失敗的,因此要先確保獲取鎖成功再進...