[MySQL] 行級鎖SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE
一、譯文
If you query data and then insert or update related data within the same transaction, the regular SELECT statement does not give enough protection. Other transactions can update or delete the same rows you just queried. InnoDB supports two types of locking reads that offer extra safety:
如果你在查詢資料,然後在同一個事務裡插入或者修改相關的資料,常規的 select 語句不會提供足夠的保護。其他的事務可以修改或者刪除你正在查詢的行。InnoDB 支援兩種可以提供安全機制的讀取鎖:
SELECT … LOCK IN SHARE MODE sets a shared mode lock on any rows that are read. Other sessions can read the rows, but cannot modify them until your transaction commits. If any of these rows were changed by another transaction that has not yet committed, your query waits until that transaction ends and then uses the latest values.
SELECT … LOCK IN SHARE MODE 在讀取的行上設定一個共享鎖,其他的session可以讀這些行,但在你的事務提交之前不可以修改它們。如果這些行裡有被其他的還沒有提交的事務修改,你的查詢會等到那個事務結束之後使用最新的值。
For index records the search encounters, SELECT … FOR UPDATE locks the rows and any associated index entries, the same as if you issued an UPDATE statement for those rows. Other transactions are blocked from updating those rows, from doing SELECT … LOCK IN SHARE MODE, or from reading the data in certain transaction isolation levels. Consistent reads ignore any locks set on the records that exist in the read view. (Old versions of a record cannot be locked; they are reconstructed by applying undo logs on an in-memory copy of the record.)
索引搜尋遇到的記錄,SELECT … FOR UPDATE 會鎖住行及任何關聯的索引條目,和你對那些行執行 update 語句相同。其他的事務會被阻塞在對這些行執行 update 操作,獲取共享鎖,或從某些事務隔離級別讀取資料等操作。一致性讀(Consistent Nonlocking Reads)會忽略在讀取檢視上的記錄的任何鎖。(舊版本的記錄不能被鎖定;它們通過應用撤銷日誌在記錄的記憶體副本上時被重建。)
All locks set by LOCK IN SHARE MODE and FOR UPDATE queries are released when the transaction is committed or rolled back.
Note
Locking of rows for update using SELECT FOR UPDATE only applies when autocommit is disabled (either by beginning transaction with START TRANSACTION or by setting autocommit to 0. If autocommit is enabled, the rows matching the specification are not locked.
所有被共享鎖和排他鎖查詢所設定的鎖都會在事務提交或者回滾之後被釋放。
注:
使用 SELECT FOR UPDATE 為 update 操作鎖定行,只適用於 autocommit 被禁用(當使用 START TRANSACTION 開始事務或者設定 autocommit 為0時)。如果 autocommit 已啟用,符合規範的行不會被鎖定。
二、總結
SELECT … LOCK IN SHARE MODE :共享鎖(S鎖, share locks)。其他事務可以讀取資料,但不能對該資料進行修改,直到所有的共享鎖被釋放。
如果事務對某行資料加上共享鎖之後,可進行讀寫操作;其他事務可以對該資料加共享鎖,但不能加排他鎖,且只能讀資料,不能修改資料。
SELECT … FOR UPDATE:排他鎖(X鎖, exclusive locks)。如果事務對資料加上排他鎖之後,則其他事務不能對該資料加任何的鎖。獲取排他鎖的事務既能讀取資料,也能修改資料。
注:普通 select 語句預設不加鎖,而CUD操作預設加排他鎖。
三、驗證
注:使用 mysql 版本為 5.7.9,事務隔離級別為InnoDB預設隔離級別 可重複讀(Repeated Read)。
對以下幾種情況進行驗證:
- 當前事務獲取共享鎖後,可以讀寫,其他事務是否可以進行讀寫操作和獲取共享鎖;
- 兩個事務同時獲取共享鎖後,是否可以進行update操作;
- 當前事務獲取排他鎖後,其他事務是否可以進行讀寫操作和獲取共享鎖;
- 是否可對一條資料加多個排他鎖;
- 行鎖和索引的關係;
- 索引資料重複率太高會導致全表掃描;
1、當前事務獲取共享鎖後,可以讀寫,其他事務是否可以進行讀寫操作和獲取共享鎖:可以讀,可以獲取共享鎖,不可以寫
當前事務可以寫:
事務1獲取某行資料共享鎖後,事務2更新該行阻塞:
事務1提交之後,事務2更新成功:
2、兩個事務同時獲取某行資料共享鎖後,是否可以進行update操作:不可以
兩個事務同時獲取某行資料共享鎖,事務1更新該行阻塞:
事務2提交之後,事務1更新成功:
3、當前事務獲取某行資料排他鎖後,其他事務是否可以對該行資料進行讀寫操作和獲取共享鎖:其他事務可以讀,不可以獲取共享鎖,不可以寫
可以讀該行資料:
不可以獲取該行資料共享鎖:
不可以更新該行資料:
4、是否可對一條資料加多個排他鎖:不可以
5、行鎖和索引的關係:查詢欄位未加索引(主鍵索引、普通索引等)時,使用表鎖
注:InnoDB行級鎖基於索引實現。
未加索引時,兩種行鎖情況為(使用表鎖):
- 事務1獲取某行資料共享鎖,其他事務可以獲取不同行資料的共享鎖,不可以獲取不同行資料的排他鎖
- 事務1獲取某行資料排他鎖,其他事務不可以獲取不同行資料的共享鎖、排他鎖
加索引後,兩種行鎖為(使用行鎖):
- 事務1獲取某行資料共享鎖,其他事務可以獲取不同行資料的排他鎖
- 事務1獲取某行資料排他鎖,其他事務可以獲取不同行資料的共享鎖、排他鎖
未加索引表結構:
未加索引,事務1獲取某行資料共享鎖,事務2獲取不同行資料共享鎖成功:
未加索引,事務1獲取某行資料共享鎖,事務2更新不同行資料阻塞:
未加索引,事務1獲取某行資料排他鎖,事務2獲取不同行資料共享鎖阻塞:
未加索引,事務1獲取某行資料排他鎖,事務2獲取不同行資料排他鎖阻塞:
加索引後表結構:
加索引後,事務1獲取某行資料共享鎖,事務2更新不同行資料成功:
加索引後,事務1獲取某行資料排他鎖,事務2獲取不同行資料共享鎖成功:
加索引後,事務1獲取某行資料排他鎖,事務2獲取不同行資料排他鎖成功:
6、索引資料重複率太高會導致全表掃描:當表中索引欄位資料重複率太高,則MySQL可能會忽略索引,進行全表掃描,此時使用表鎖。可使用 force index 強制使用索引。
表結構:
CREATE TABLE `room` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) NOT NULL,
`username` varchar(200) NOT NULL DEFAULT '',
`state` varchar(255) NOT NULL DEFAULT '-1',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `index_uid` (`uid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
表資料:
獲取 uid = ‘11’ 的資料的行鎖並更新,但更新失敗:
降低資料重複率,更新成功:
強制使用索引,更新成功:force index(index_uid)
注:此處如果使用表鎖,為何其他事務可以獲取排他鎖?
答:由於使用 force index
,而 InnoDB 行級鎖基於索引實現,因此此處使用的是行鎖。
四、InnoDB 行鎖型別簡介
InnoDB行鎖的三種類型:
- Record Lock:對索引項加鎖,鎖定符合條件的行。其他事務不能修改和刪除加鎖項;
- Gap Lock:對索引項之間的“間隙”加鎖,鎖定記錄的範圍,不包含索引項本身。其他事務不能再鎖範圍內插入資料;
- Next-key Lock: 鎖定索引項本身和索引範圍,即Record Lock 和 Gap Lock 的結合。可解決幻讀問題。
相關推薦
[MySQL] 行級鎖SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE
一、譯文 If you query data and then insert or update related data within the same transaction, the regular SELECT statement does not
深入理解SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE
概念和區別 SELECT ... LOCK IN SHARE MODE走的是IS鎖(意向共享鎖),即在符合條件的rows上都加了共享鎖,這樣的話,其他session可以讀取這些記錄,也可以繼續新增IS鎖,但是無法修改這些記錄直到你這個加鎖的session執行完成(否則直接鎖等待超時)。 SELE
mysql lock in share mode 和 select for update
原文連結:http://blog.csdn.net/d6619309/article/details/52688250 工作需要,接觸到以下兩個MySQL sql語法: select lock in share mode select for update 1
Mysql加鎖過程詳解(4)-select for update/lock in share mode 對事務並發性影響
per inno targe 允許 evel transacti 修改 not null warn select for update/lock in share mode 對事務並發性影響 事務並發性理解 事務並發性,粗略的理解就是單位時間內能夠執行的事務數量,常見的單
mysql 行級鎖的使用
package com.hacker.jdbc.transactional; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLExcept
你真的會用mysql行級鎖嗎?mysql 行級鎖全解析
在網際網路大併發應用大行其道的今天,應用的開發總是離不開鎖,在分散式應用中,最常見的莫過於基於資料庫的行級鎖了,由於網際網路公司中比較主流的資料庫還是mysql,所以這一話題繞不開的就是mysql了,但是由於mysql中innoDb引擎特殊的機制,經常一不小心就會發生死鎖,本次咱們就來聊一聊基於mysql
MySQL鎖的用法之行級鎖
數據 更新 能夠 使用 date 技術 adding strong 一個 行級鎖是MySQL中粒度最小的一種鎖,他能大大減少數據庫操作的沖突。但是粒度越小,實現的成本也越高。MYISAM引擎只支持表級鎖,而INNODB引擎能夠支持行級鎖,下面的內容也是針對INNOD
MySQL中的行級鎖,表級鎖,頁級鎖
In 回退 常用 info 部分 title 一個 相關 鍵值 轉載:https://blog.csdn.net/zp522123428/article/details/75413745##s4 在計算機科學中,鎖是在執行多線程時用於強行限制資源訪問的同步機制,即用於在並發
MySQL中的行級鎖、表級鎖、頁級鎖
常用 一點 存儲引擎 rac 鎖定 方法 線程 加鎖 計算機 在計算機科學中,鎖是在執行多線程時用於強行限制資源訪問的同步機制,即用於在並發控制中保證對互斥要求的滿足。 在DBMS中,可以按照鎖的粒度把數據庫鎖分為行級鎖(INNODB引擎)、表級鎖(MYISA
MySQL表級鎖、行級鎖、頁級鎖詳細介紹
MySQL的鎖機制比較簡單,其最顯著的特點是不同的儲存引擎支援不同的鎖機制。 MyISAM和MEMORY儲存引擎採用的是表級鎖(table-level-locking); BDB儲存引擎採用的是頁面鎖(page-level-locking),同時也支援表級鎖; InnoDB儲存引擎既支援
MySQL中的行級鎖,表級鎖,頁級鎖
在電腦科學中,鎖是在執行多執行緒時用於強行限制資源訪問的同步機制,即用於在併發控制中保證對互斥要求的滿足。 在DBMS中,可以按照鎖的粒度把資料庫鎖分為行級鎖(INNODB引擎)、表級鎖(MYISAM引擎)和頁級鎖(BDB引擎 )。 行級鎖 行級鎖是Mysql中鎖定粒度最細的一種
如何理解資料庫MySQL的表級鎖、行級鎖、頁鎖問題?
從鎖的粒度進行對資料庫進行劃分等級 表級鎖 行級鎖 頁級鎖(這個不常用) (1)MySQL的表級鎖兩種模式: 1. 表級共享讀鎖(共享鎖): 也就是在MyISAM引擎下,如果對一個表加了讀鎖的話,那
MySQL 中的行級鎖、表級鎖和頁級鎖(不看後悔,看了必懂)
行級鎖 行級鎖是 MySQL 中鎖定粒度最細的一種鎖,表示只針對當前操作的行進行加鎖。行級鎖分為共享鎖和排他鎖。 特點:加鎖開銷大,會出現死鎖,鎖定粒度最小,發生鎖衝突的概率最低,併發度最高 頁級鎖 頁級鎖是 MySQL 中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。
詳述 MySQL 中的行級鎖、表級鎖和頁級鎖
在電腦科學中,鎖是在執行多執行緒時用於強行限制資源訪問的同步機制,即用於在併發控制中保證對互斥要求的滿足。 在資料庫的鎖機制中,咱們介紹過在 DBMS 中,可以按照鎖的粒度把資料庫鎖分為行級鎖(InnoDB 引擎)、表級鎖(MyISAM 引擎)和頁級鎖(BDB
mysql鎖機制之行級鎖
鎖是在執行多執行緒時用於強行限定資源訪問的同步機制,資料庫鎖根據鎖的粒度可分為行級鎖,表級鎖和頁級鎖行級鎖行級鎖是mysql中粒度最細的一種鎖機制,表示只對當前所操作的行進行加鎖,行級鎖發生衝突的概率很低,其粒度最小,但是加鎖的代價最大。行級鎖分為共享鎖和排他鎖。特點:開銷大
mysql 實驗論證 innodb表級鎖與行級鎖
innodb 的行鎖是在有索引的情況下,沒有索引的表是鎖定全表的. 表鎖演示(無索引) 操作1 操作2 處於等待狀
Mysql的行級鎖與表級鎖
在電腦科學中,鎖是在執行多執行緒時用於強行限制資源訪問的同步機制,即用於在併發控制中保證對互斥要求的滿足。 在DBMS中,可以按照鎖的粒度把資料庫鎖分為行級鎖(INNODB引擎)、表級鎖(MYISAM引擎和INNODB儲存引擎)。 行級鎖 行級鎖是Mysql中鎖定粒度最細的一種鎖,表示只針對當前操作的行進行加
mysql:如何解決資料修改衝突(事務+行級鎖的實際運用)
摘要:最近做一個接診需求遇到一個問題,假設一個訂單諮詢超過3次就不能再接診,但如果兩個醫生同時對該訂單進行諮詢,查資料庫的時候都能查到滿足條件的該訂單,那兩個醫生都能接診,所謂接診可以理解為更新了接診次數,此時就出現了bug(接診超過3次)。 其實這個問題看似很明朗,但想要完全解決需要理解事務和鎖的概念,以前
oracle行級鎖
Oracle有許多的鎖,各種鎖的效用是不一樣的。下面重點介紹Oracle行級鎖,Oracle行級鎖只對使用者正在訪問的行進行鎖定。可以更好的保證資料的安全性,需要的朋友可以瞭解下 Oracle有許多的鎖,各種鎖的效用是不一樣的。下面重點介紹Oracle行級鎖,Oracle行級鎖只對使用者正在訪問
sql server行級鎖,排它鎖,共享鎖的使用
鎖的概述 一. 為什麼要引入鎖 多個使用者同時對資料庫的併發操作時會帶來以下資料不一致的問題: 丟失更新 A,B兩個使用者讀同一資料並進行修改,其中一個使用者的修改結果破壞了另一個修改的結果,比如訂票系統 髒讀 A使用者修改了資料,隨後B使用者又讀出該資料,但A使用者因為某些原因取消了對資