Artikel ini membawakan anda pengetahuan yang berkaitan tentang mysql, yang terutamanya memperkenalkan pengetahuan berkaitan tentang kunci peringkat baris dalam kunci Baris InnoDB, yang juga dipanggil kunci rekod, seperti namanya, adalah Mari kita lihat pada kunci yang ditambahkan pada rekod saya harap ia akan membantu semua orang.
Pembelajaran yang disyorkan: tutorial video mysql
Kunci baris, juga dikenali sebagai kunci rekod, seperti namanya, ialah kunci ditambah ke dalam rekod. Tetapi sila ambil perhatian bahawa rekod ini merujuk kepada mengunci entri indeks pada indeks. Ciri pelaksanaan kunci baris InnoDB ini bermakna InnoDB menggunakan kunci peringkat baris hanya apabila data diambil melalui keadaan indeks Jika tidak, InnoDB akan menggunakan kunci jadual.
Sama ada menggunakan indeks kunci utama, indeks unik atau indeks biasa, InnoDB akan menggunakan kunci baris untuk mengunci data.
Kunci baris hanya boleh digunakan jika pelan pelaksanaan benar-benar menggunakan indeks: walaupun medan indeks digunakan dalam keadaan, sama ada untuk menggunakan indeks untuk mendapatkan data ditentukan oleh MySQL dengan menilai kos yang berbeza rancangan pelaksanaan. Jika MySQL percaya bahawa imbasan jadual penuh adalah lebih cekap Contohnya, untuk beberapa jadual yang sangat kecil, ia tidak akan menggunakan indeks Dalam kes ini, InnoDB akan menggunakan kunci meja dan bukannya kunci baris.
Pada masa yang sama, apabila kami mendapatkan semula data menggunakan keadaan julat dan bukannya syarat kesamarataan dan meminta kunci, InnoDB akan mengunci entri indeks rekod data sedia ada yang memenuhi syarat.
Tetapi kunci baris pun terbahagi kepada pelbagai jenis dalam InnoDB. Dalam erti kata lain, walaupun kunci baris ditambahkan pada rekod yang sama, jika jenisnya berbeza, kesannya akan berbeza.
Di sini kita masih menggunakan jadual guru sebelumnya, menambah indeks dan memasukkan beberapa rekod.
mysql> desc teacher; +--------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+--------------+------+-----+---------+-------+ | number | int(11) | NO | PRI | NULL | | | name | varchar(100) | YES | MUL | NULL | | | domain | varchar(100) | YES | | NULL | | +--------+--------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> select * from teacher; +--------+------+--------+ | number | name | domain | +--------+------+--------+ | 1 | T | Java | | 3 | M | Redis | | 9 | X | MQ | | 15 | O | Python | | 21 | A | Golang | +--------+------+--------+ 5 rows in set (0.00 sec)
Mari kita lihat jenis kunci baris yang biasa digunakan.
Juga dipanggil kunci rekod, ia hanya mengunci satu rekod Nama jenis rasmi ialah: LOCK_REC_NOT_GAP. Sebagai contoh, gambarajah skema untuk menambah kunci rekod pada rekod dengan nilai nombor 9 adalah seperti berikut:
Kunci rekod dibahagikan kepada kunci S dan kunci X Apabila a Selepas urus niaga memperoleh kunci rekod jenis S bagi sesuatu rekod, urus niaga lain boleh terus memperoleh kunci rekod jenis S bagi rekod, tetapi mereka tidak boleh terus memperoleh kunci rekod jenis X apabila urus niaga memperoleh kunci rekod X-; jenis kunci rekod rekod, Urus niaga lain tidak boleh terus memperoleh kunci rekod jenis S mahupun kunci rekod jenis X untuk rekod ini.
T1 | T2 |
---|---|
begin; | |
select * from teacher where number=9 for update; | |
select * from teacher where number=9 for update; # 阻塞 |
MySQL boleh menyelesaikan sebahagian masalah bacaan hantu di bawah tahap pengasingan BACA BERULANG Anda boleh menggunakan penyelesaian MVCC atau mengunci. Walau bagaimanapun, terdapat masalah apabila menggunakan penyelesaian penguncian Apabila urus niaga melakukan operasi baca buat kali pertama, rekod hantu tersebut belum wujud dan kami tidak boleh menambah kunci rekod pada rekod hantu ini. InnoDB mencadangkan sejenis kunci yang dipanggil Gap Locks Nama jenis rasmi ialah: LOCK_GAP Kami juga boleh memanggilnya sebagai kunci jurang.
Kunci jurang pada dasarnya mengunci jurang sebelum dan selepas indeks, tetapi tidak mengunci indeks itu sendiri.
T1 | T2 |
---|---|
begin; | |
update teacher set domain=‘Redis’ where name=‘M’; | |
insert into teacher value(23,‘B’,‘docker’); # 阻塞 | |
insert into teacher value(23,‘B’,‘docker’); # 阻塞 |
事务T1会对([A, 21], [M, 3])、([M, 3], [O, 15])之间进行上gap锁,如下图中所示:
意味着不允许别的事务在这条记录前后间隙插入新记录,所以T2就不能插入。
但是当SQL语句变为:
insert into teacher value(70,'P','docker');
能插入吗?当然能,因为(70,‘P’)这条记录不在被锁的区间内。
现在有表,表中有记录如下:
<span style="font-family: " microsoft yahei sans gb helvetica neue tahoma arial sans-serif>list = ['su liang','hacker','ice']<br>list.insert(1,'kiko')<br>print(list)<br>#结果:['su liang', 'kiko', 'hacker', 'ice']</span><br>
开启一个事务:
begin;SELECT * FROM test1 WHERE number = 3 FOR UPDATE;
开启另外一个事务:
INSERT INTO test1 (id, number) VALUES (2, 1); # 阻塞 INSERT INTO test1 (id, number) VALUES (3, 2); # 阻塞 INSERT INTO test1 (id, number) VALUES (6, 8); # 阻塞 INSERT INTO test1 (id, number) VALUES (8, 8); # 正常执行 INSERT INTO test1 (id, number) VALUES (9, 9); # 正常执行 INSERT INTO test1 (id, number) VALUES (10, 12); # 正常执行 UPDATE test1 SET number = 5 WHERE id = 11 AND number = 12; # 阻塞
为什么(6,8)不能执行,(8,8)可以执行?这个间隙锁的范围应该是[1,8],最后一个语句为什么不能执行?
解决思路:画一个number的索引数据存放的图,然后根据间隙锁的加锁方式,把锁加上,就能很快明白答案。
有时候我们既想锁住某条记录,又想阻止其他事务在该记录前边的间隙插入新记录,所以InnoDB就提出了一种称之为Next-Key Locks的锁,官方的类型名称为:LOCK_ORDINARY,我们也可以简称为next-key锁。next-key锁的本质就是
一个记录锁和一个gap锁的合体。
默认情况下,InnoDB以REPEATABLE READ隔离级别运行。在这种情况下,InnoDB使用Next-Key Locks锁进行搜索和索引扫描,这可以防止幻读的发生。
我们说一个事务在插入一条记录时需要判断一下插入位置是不是被别的事务加了所谓的gap锁(next-key锁也包含gap 锁,后边就不强调了),如果有的话,插入操作需要等待,直到拥有gap锁的那个事务提交。
但是InnoDB规定事务在等待的时候也需要在内存中生成一个锁结构,表明有事务想在某个间隙中插入新记录,但是现在处于等待状态。这种类型的锁命名为Insert Intention Locks,官方的类型名称为:LOCK_INSERT_INTENTION,我们也可以称为插入意向锁。
可以理解为插入意向锁是一种锁的的等待队列,让等锁的事务在内存中进行排队等待,当持有锁的事务完成后,处于等待状态的事务就可以获得锁继续事务了。
锁的的维护是需要成本的,为了节约资源,MySQL在设计提出了了一个隐式锁的概念。一般情况下INSERT操作是不加锁的,当然真的有并发冲突的情况下下,还是会导致问题的。
所以MySQL中,一个事务对新插入的记录可以不显式的加锁,但是别的事务在对这条记录加S锁或者X锁时,会去检查索引记录中的trx_id隐藏列,然后进行各种判断,会先帮助当前事务生成一个锁结构,然后自己再生成一个锁结构后进入等待状态。但是由于事务id的存在,相当于加了一个隐式锁。
这样的话,隐式锁就起到了延迟生成锁的用处。这个过程,我们无法干预,是由引擎自动处理的,对我们是完全透明的,我们知道下就行了。
所谓的锁其实是一个内存中的结构,在事务执行前本来是没有锁的,也就是说一开始是没有锁结构和记录进行关联的,当一个事务想对这条记录做改动时,首先会看看内存中有没有与这条记录关联的锁结构,当没有的时候就会在内存中生成一个锁结构与之关联。比方说事务T1要对记录做改动,就需要生成一个锁结构与之关联。
锁结构里至少要有两个比较重要的属性:
当事务T1改动了条记录后,就生成了一个锁结构与该记录关联,因为之前没有别的事务为这条记录加锁,所以is_waiting 属性就是false,我们把这个场景就称之为获取锁成功,或者加锁成功,然后就可以继续执行操作了。
在事务T1提交之前,另一个事务T2也想对该记录做改动,那么先去看看有没有锁结构与这条记录关联,发现有一个锁结构与之关联后,然后也生成了一个锁结构与这条记录关联,不过锁结构的is_waiting属性值为true,表示当前事务需要等待,我们把这个场景就称之为获取锁失败,或者加锁失败,或者没有成功的获取到锁。
在事务T1提交之后,就会把该事务生成的锁结构释放掉,然后看看还有没有别的事务在等待获取锁,发现了事务T2还在等待获取锁,所以把事务T2对应的锁结构的is_waiting属性设置为false,然后把该事务对应的线程唤醒,让它继续执行,此时事务T2就算获取到锁了。这种实现方式非常像并发编程里AQS的等待队列。
对一条记录加锁的本质就是在内存中创建一个锁结构与之关联。那么,一个事务对多条记录加锁时,是不是就要创建多个锁结构呢?比如:
SELECT * FROM teacher LOCK IN SHARE MODE;
很显然,这条语句需要为teacher表中的所有记录进行加锁。那么,是不是需要为每条记录都生成一个锁结构呢?其实理论上创建多个锁结构没有问题,反而更容易理解。但是如果一个事务要获取10,000条记录的锁,要生成10,000个这样的结构,不管是执行效率还是空间效率来说都是很不划算的,所以实际上,并不是一个记录一个锁结构。
当然锁结构实际是很复杂的,我们大概了解下里面包含哪些元素。
基本上来说,同一个事务里,同一个数据页面,同一个加锁类型的锁会保存在一起。
推荐学习:mysql视频教程
Atas ialah kandungan terperinci Mata pengetahuan MySQL: kunci peringkat baris dalam InnoDB. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!