当前位置: 首页 > 后端技术 > Java

记录MySql更新会锁定哪些范围的数据

时间:2023-04-02 09:29:50 Java

1。背景在项目中,我们经常使用update语句,那么表中哪些记录会被update语句锁定呢?这里我们模拟一些简单的情况。这是我自己的理解。如有理解错误请指出2.前置知识2.1数据库隔离级别mysql>showvariableslike'transaction_isolation';+----------------------+----------------+|变量名|值|+----------------------+----------------+|事务隔离|REPEATABLE-READ|+---------------------+----------------+1rowinset(0.00sec)2.2数据库版本mysql>selectversion();+-----------+|版本()|+------------+|8.0.28|+------------+1rowinset(0.00sec)2.3数据库的存储引擎mysql>showvariableslike'%storage_engine%';+-------------------------------+------------+|变量名|值|+-----------------------------+------------+|默认存储引擎|数据库||default_tmp_storage_engine|数据库||disabled_storage_engines|||internal_tmp_mem_storage_engine|临时表|+------------------------------+------------+4rowsinset(0.01sec)2.4是给记录加锁还是给索引加索引锁,那么如果表没有创建索引,是否它只是添加到表中吗?其实不是,它也是加了索引,会有一个默认的Recordlocks,总是锁住索引记录,即使一个表定义了没有索引。对于这种情况,InnoDB创建一个隐藏的聚簇索引并将该索引用于记录锁定参考链接:https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-intention-locks2。5update...where加锁的基本单位是UPDATE...WHERE...对搜索遇到的每条记录设置一个独占的next-key锁这里可以理解加锁的单位是:next-keylock2.6row-levellock2.6.1RecordLocks记录锁,即只有一条记录会被锁定。其实就是锁定这条记录的索引。记录锁是索引记录上的锁。例如,SELECTc1FROMtWHEREc1=10FORUPDATE;防止任何其他事务插入、更新或删除t.c1值为10.2.6.2的行GapLocks间隙锁,间隙锁是在索引记录之间的间隙上的锁,即锁定一个范围。打开前和打开后间隔,不包括记录本身。如果使用单列唯一索引值更新间隙锁,它将退化为记录锁。间隙锁的目的:防止新数据插入间隙,防止已有数据更新到间隙。对于使用唯一索引锁定行以搜索>查找唯一行的语句,不需要间隙锁定。(这不包括搜索条件只包括多列唯一索引的某些列的情况;在这种情况下,确实会发生间隙锁定。)2.6.3Next-KeyLocksNext-KeyLock是一个组合索引记录上的记录锁和索引记录之前的间隙上的间隙锁。也是锁定一个范围,打开前面再关闭范围。包括唱片本身。如果索引值包括1,5,10,30,那么下一个keylock可能覆盖以下范围(negativeinfinity,1](1,115(5,10](10,30](30,positiveinfinity)negative无穷大指的是负无穷大,正无穷大指的是正无穷大。2.6.4测试锁表的表结构createtabletest_record_lock(idintnotnullcomment'主键',ageintnullcomment'age,commonindex',namevarchar(10)nullcomment'name,noindex',constrainttest_record_lock_pkprimarykey(id))comment'Testrecordlock';createindextest_record_lock_age_indexontest_record_lock(age);2.6.5测试表中的数据mysql>select*fromtest_record_lock;+----+------+-------+|编号|年龄|姓名|+----+------+------+|1|10|张三||5|20|李斯||8|25|王五|+----+-----+--------+3rowsinset(0.00sec)2.7查看数据库当前锁select*fromperformance_schema.data_locks;字段解释:字段值解释lock_typeTABLE表加锁RECORD记录加锁lock_modeIXintentexclusivelockXorSnext-keylock
加锁记录本身和记录前的间隙X,REC_NOT_GAPRecordLockOnlylock记录本身S,REC_NOT_GAPRecordLockonlylocktherecorditselfX,GAPgaplockX,INSERT_INTENTIONinsertintentionlocklock_data具体数字表示主键的值,第一个值:普通索引的值
第二个Avalue:主键值问题:X,GAP可以理解为X锁退化为GAP锁。3.测试数据锁定3.1唯一索引测试适用于单个字段的唯一索引,不适用于多个字段的唯一索引3.1.1等价更新-记录存在性说明:加next-key锁,则锁定范围records是(1,5)。因为是唯一索引,查询的值存在,所以next-key锁退化为record锁,即最后只锁id=5的那行数据。其余数据不受影响3.1.2等价Query-recorddoesnotexist-01解释:加上next-key锁,则锁住的记录范围为(5,8)。因为是唯一索引,查询value不存在,next-keylock退化为gap,即finallock的数据范围为(5,8),其余数据不受影响。3.1.3等价更新-记录不存在-023.1.4范围更新1.小于等于最大临界值此时可以发现表中扫描的记录都加了nextkeylock(锁被添加到索引)2.大于或等于最小阈值mysql>begin;QueryOK,0rowsaffected(0.01sec)mysql>updatetest_record_locksetname='aaa'whereid>=1;QueryOK,3行受影响(0.00秒)行匹配:3更改:3警告:0mysql>selectLOCK_TYPE,INDEX_NAME,LOCK_MODE,LOCK_DATAfromperformance_schema.data_locks;+------------+------------+--------------+------------------------+|锁类型|INDEX_NAME|锁定模式|LOCK_DATA|+-----------+------------+------------+----------------------+|表|空|九|空||记录|初级|X,REC_NOT_GAP|1||记录|×|8||记录|初级|×|5|+------------+------------+-----------------+-----------------------+5rowsinset(0.01sec)此时只能将小于最小临界值的记录插入表中.3.NormalScope3.2普通索引测试3.2.1等价更新-记录存在性说明:先给普通索引age加上next-keylock,锁定范围为(10,20]next-keylock也会锁这条记录,所以inid索引的值等于5,加上一个RecordLock,因为是普通索引,值还存在,所以会在这条记录的下一个区间加一个gapLockGapLock,锁定范围is(20,25)3.2.2等价update-Therecorddoesnotexist解释:获取next-key锁的范围是(10,20],因为需要更新的记录不存在,next-key锁退化为间隙锁,所以加锁的范围是(10,20),因为普通的索引和记录都不存在,所以不需要再去寻找下一个区间3.2.3范围更新解释:普通索引的范围更新,next-key-lock不会回退到gaplock3.3无索引更新从上图可以看出,更新无索引的数据表是危险的,需要处理小心。在没有索引的情况下进行更新将导致全表扫描,从而导致对所有扫描记录添加next-key锁。3、参考链接1,https://dev.mysql。com/doc/refman/8.0/en/innodb-locking.html#innodb-intention-locks2,https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html