方达 發表於 2025-12-29 11:50:58

MySQL查看事务与锁的操作示例小结

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">1. MySQL如何查看事务与锁🔒</a></li><li><a href="#_label1">2. 不同事务隔离级别下的锁类型验证</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_0">2.1 RC级别下的验证</a></li><ul class="third_class_ul"><li><a href="#_label3_1_0_0">2.1.1 共享锁(S锁)</a></li><li><a href="#_label3_1_0_1">2.1.2 排它锁(X锁🔒)</a></li></ul><li><a href="#_lab2_1_1">2.2 RR级别下的验证</a></li><ul class="third_class_ul"><li><a href="#_label3_1_1_2">2.2.1 共享锁(S锁)</a></li><li><a href="#_label3_1_1_3">2.2.2 排它锁(X锁🔒)</a></li></ul></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>1. MySQL如何查看事务与锁🔒</h2>
<div class="jb51code"><pre class="brush:sql;">-- 1. 查看当前运行的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
-- 2. 查看锁信息
-- 2.1 MySQL 5.7
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
-- 2.2 MySQL 8.0+
SELECT * FROM performance_schema.data_locks;
SELECT * FROM performance_schema.data_lock_waits;</pre></div>
<p>从【<a href="https://www.jb51.net/database/301691sa5.htm" target="_blank">MySQL-InnoDB锁、事务与MVCC</a>】文章可以看出来,锁有下面几种分类:</p>
<ul><li><strong>按锁模式分为</strong>:共享锁(S锁)、排它锁(X锁)。</li><li><strong>按锁粒度分为</strong>:表锁、行锁。</li><li><strong>表锁分为</strong>:表级S锁、表级X锁、表级IS锁(意向共享锁)、表级IX锁(意向排它锁)。<ul><li><strong>IS锁和IX锁的目的</strong>:只是为了后续 在加表级别的S锁和X锁时 判断 表中是否有已经被加锁的&nbsp;<strong>记录</strong>,以避免用遍历的方式来查看表中有没有上锁的记录。</li></ul></li><li><strong>行锁分为</strong>:<strong><span>记录锁(Record Lock)、间隙锁(Gap Lock)、临键锁(Next-key Lock,Gap锁 + 记录锁)、隐式锁</span></strong>。</li></ul>
<p><span><strong>对于MySQL的InnoDB存储引擎来说,不同事务隔离级别下使用的锁不同</strong></span>:</p>
<ul><li><strong>READ COMMITTED(RC,读已提交)</strong>:<strong><span><span>只有 记录锁(Record Lock),没有 间隙锁(Gap Lock)或 临键锁(Next-Key Lock)</span></span></strong>。</li><li><strong>REPEATABLE READ(RR,可重复读)</strong>:<strong><span><span>默认使用 Next-Key Lock(记录锁+间隙锁),</span><span>注意这里说的是【默认】,并不意味着RR级别下使用行级锁时全都用的是 Next-Key。</span></span></strong></li></ul>
<p class="maodian"><a name="_label1"></a></p><h2>2. 不同事务隔离级别下的锁类型验证</h2>
<p>以下测试基于MySQL_8.0.30</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183464.png" /></p>
<p>用来验证的cus_info表结构:</p>
<div class="jb51code"><pre class="brush:sql;">-- test.cus_info definition
CREATE TABLE `cus_info` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`cus_id` varchar(21) NOT NULL COMMENT '客户编号',
`phone_num` varchar(11) NOT NULL COMMENT '手机号',
`nick_name` varchar(20) NOT NULL COMMENT '昵称',
`sex` varchar(1) NOT NULL COMMENT '性别,0-女,1-男',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_ci` (`cus_id`) USING BTREE, -- 二级索引:唯一索引
UNIQUE KEY `uk_pn` (`phone_num`) USING BTREE -- 唯一索引
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='客户信息表';
-- 插入语句
INSERT INTO cus_info (cus_id, phone_num, nick_name, sex) VALUES('200606011708203560002', '10000000002', '盖世无双', '0');
-- 更新语句
UPDATE cus_info SET cus_id='200606011708203560002', phone_num='10000000002', nick_name='盖世无双', sex='0' WHERE id=2;
-- 查询语句
SELECT id, cus_id, phone_num, nick_name, sex FROM cus_info WHERE id=2;</pre></div>
<p><strong>表数据如下</strong>:id(1, 2, 3, 5, 7, 8)</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183421.png" /></p>
<p class="maodian"><a name="_lab2_1_0"></a></p><h3>2.1 RC级别下的验证</h3>
<p>先查看一下事务隔离级别:</p>
<div class="jb51code"><pre class="brush:sql;">-- 切换到test库
mysql&gt; use test;
-- 查询事务隔离级别
mysql&gt; show variables like '%isolation%';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.00 sec)</pre></div>
<p class="maodian"><a name="_label3_1_0_0"></a></p><h4>2.1.1 共享锁(S锁)</h4>
<p><span><strong>普通的select语句,InnoDB存储引擎不会加任何锁</strong></span>。</p>
<div class="jb51code"><pre class="brush:sql;">mysql&gt; start transaction;
Query OK, 0 rows affected (0.00 sec)
-- 普通的select语句,InnoDB存储引擎不会加任何锁。可以通过 performance_schema.data_locks表查看。
mysql&gt; select * from cus_info where id &gt; 2 and id &lt; 7;
-- 查询结果展示省略
-- 加 共享锁(S锁)
mysql&gt; select * from cus_info where id &gt; 2 and id &lt; 7 for share;
+----+-----------------------+-------------+-----------+-----+
| id | cus_id                | phone_num   | nick_name | sex |
+----+-----------------------+-------------+-----------+-----+
|3 | 200606011708203560003 | 10000000003 | 默默      | 0   |
|5 | 200606011708203560005 | 10000000005 | 王      | 0   |
+----+-----------------------+-------------+-----------+-----+
2 rows in set (0.00 sec)</pre></div>
<p><strong>查询锁信息</strong>:performance_schema.data_locks</p>
<div class="jb51code"><pre class="brush:sql;">select `engine`, object_schema, object_name, index_name, lock_type, lock_mode, lock_status, lock_data from performance_schema.data_locks;</pre></div>
<p>可以看到:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; ① 给表cus_info加了 表级别的IS锁(意向共享锁)。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;② 给id(主键)为3和5的两条记录加了 Record Lock(记录锁)、S锁(共享锁),并且不是Gap锁。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183411.jpg" /></p>
<div class="jb51code"><pre class="brush:sql;">-- 测试完后提交或回滚事务
mysql&gt; rollback; -- 或者 commit
Query OK, 0 rows affected (0.00 sec)</pre></div>
<p class="maodian"><a name="_label3_1_0_1"></a></p><h4>2.1.2 排它锁(X锁🔒)</h4>
<div class="jb51code"><pre class="brush:sql;">mysql&gt; start transaction;
Query OK, 0 rows affected (0.00 sec)</pre></div>
<p>开启事务后,我们先来看一下 information_schema库的INNODB_TRX视图信息,可以看到没有任何数据,由此也可以看出来<span><span> </span><strong><span>start transaction; 开启一个事务并没有让 MySQL真正开始分配事务编号(trx_id)</span></strong></span>。</p>
<div class="jb51code"><pre class="brush:sql;">mysql&gt; select * from information_schema.INNODB_TRX;
Empty set (0.00 sec)</pre></div>
<p>再执行一个 普通的select语句,再看看 INNODB_TRX 视图信息:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;trx_id(事务编号)、trx_state(事务状态,running运行中)、trx_started(事务开始时间)、trx_isolation_level(事务隔离级别)。<span><strong>注意trx_id(事务编号)的值,等下看看会发生什么变化</strong></span>。此时还没有加任何锁,所以 performance_schema.data_locks表中没有任何信息。</p>
<div class="jb51code"><pre class="brush:sql;">mysql&gt; select * from cus_info where id &gt; 2 and id &lt; 7;
+----+-----------------------+-------------+-----------+-----+
| id | cus_id                | phone_num   | nick_name | sex |
+----+-----------------------+-------------+-----------+-----+
|3 | 200606011708203560003 | 10000000003 | 默默      | 0   |
|5 | 200606011708203560005 | 10000000005 | 王      | 0   |
+----+-----------------------+-------------+-----------+-----+
2 rows in set (0.00 sec)
-- 这里只查看事务的部分信息(INNODB_TRX视图列太多了,只展示现在需要的)
mysql&gt; select trx_id, trx_state, trx_started, trx_isolation_level from information_schema.INNODB_TRX;
+-----------------+---------------------+-----------+---------------------+---------------------+
| trx_id          | trx_mysql_thread_id | trx_state | trx_started         | trx_isolation_level |
+-----------------+---------------------+-----------+---------------------+---------------------+
| 284035063683520 |                   8 | RUNNING   | 2025-12-28 17:28:27 | READ COMMITTED      |
+-----------------+---------------------+-----------+---------------------+---------------------+
1 row in set (0.00 sec)
mysql&gt; select * from performance_schema.data_locks;
Empty set (0.00 sec)</pre></div>
<h5>1. Update操作</h5>
<div class="jb51code"><pre class="brush:sql;">mysql&gt; update cus_info set sex=1 where id=5;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1Changed: 1Warnings: 0
-- 查看 information_schema.INNODB_TRX
mysql&gt; select trx_id, trx_mysql_thread_id, trx_state,
    -&gt; trx_started, trx_isolation_level from information_schema.INNODB_TRX;
+--------+---------------------+-----------+---------------------+---------------------+
| trx_id | trx_mysql_thread_id | trx_state | trx_started         | trx_isolation_level |
+--------+---------------------+-----------+---------------------+---------------------+
|20301 |                   8 | RUNNING   | 2025-12-28 17:28:27 | READ COMMITTED      |
+--------+---------------------+-----------+---------------------+---------------------+
1 row in set (0.00 sec)</pre></div>
<p>查看&nbsp;information_schema.INNODB_TRX,发现 trx_id 发生了变化。</p>
<p><strong>查看锁信息</strong>:performance_schema.data_locks,可以看到:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; ① 给表cus_info加了 表级别的IX锁(意向排他锁)。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;② 给id(主键)为5的记录加了 Record Lock(记录锁)、X锁(排他锁),并且不是Gap锁。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183453.png" /></p>
<h5>2. Delete操作</h5>
<p>接着上面的继续执行</p>
<div class="jb51code"><pre class="brush:sql;">mysql&gt; delete from cus_info where id=3;
Query OK, 1 row affected (0.00 sec)</pre></div>
<p><strong>查看锁信息</strong>:performance_schema.data_locks</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183460.png" />为了不影响下面的 select ... for update; 这里我们先回滚事务。</p>
<div class="jb51code"><pre class="brush:sql;">-- 为了不影响下面的 select ... for update; 这里我们先回滚事务
mysql&gt; rollback; -- 或者 commit
Query OK, 0 rows affected (0.00 sec)</pre></div>
<h5>3.隐式锁和RC级别没有Gap锁的验证(Select...for update与Insert)</h5>
<p><strong>1)、开启事务1</strong>,并执行 select...for update 操作:</p>
<div class="jb51code"><pre class="brush:sql;">-- 开启事务1(spring框架中的事务管理器 DataSourceTransactionManager 就是这么开启一个事务的)
mysql&gt; set autocommit = OFF;
Query OK, 0 rows affected (0.00 sec)
mysql&gt; select * from cus_info where id &gt; 3 and id &lt; 8 for update;
+----+-----------------------+-------------+-----------+-----+
| id | cus_id                | phone_num   | nick_name | sex |
+----+-----------------------+-------------+-----------+-----+
|5 | 200606011708203560005 | 10000000005 | 王      | 0   |
|7 | 200606011708203560007 | 10000000007 | 赵      | 1   |
+----+-----------------------+-------------+-----------+-----+
2 rows in set (0.00 sec)</pre></div>
<p><strong>查看锁信息如下</strong>:只对(3, 8)这个区间里面 <span><strong>已存在的数据</strong></span>(id = 5 和 id = 7)进行加锁操作,<span><strong>不会</strong></span><span><strong>对(3, 8)这个区间范围本身加锁</strong></span>。注意看这里加的 不是Gap锁,而是 行级排它锁。</p>
<p>这次,我们多查看一个列(engine_transaction_id,事务编号),当前事务1的事务编号为20307</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183541.png" /></p>
<p><strong>2)、开启事务2</strong>,执行 insert 操作,可以看到 insert 成功了,说明事务1确实没有对(3, 8)这个区间范围本身加锁。由此可以说明,<strong><span><span>RC事务隔离级别下对于表中的记录 没有 Gap锁(间隙锁),只有 记录锁(Record Lock)</span></span></strong>。</p>
<div class="jb51code"><pre class="brush:sql;">-- 1. 开启事务2
mysql&gt; start transaction;
Query OK, 0 rows affected (0.00 sec)
-- 2. 在insert前先select验证一下
mysql&gt; select * from cus_info where id &gt; 3 and id &lt; 8;
+----+-----------------------+-------------+-----------+-----+
| id | cus_id                | phone_num   | nick_name | sex |
+----+-----------------------+-------------+-----------+-----+
|5 | 200606011708203560005 | 10000000005 | 王      | 0   |
|7 | 200606011708203560007 | 10000000007 | 赵      | 1   |
+----+-----------------------+-------------+-----------+-----+
2 rows in set (0.00 sec)
-- 3. insert id = 6 的记录成功了,说明事务1确实没有对(3, 8)这个区间范围本身加锁。
mysql&gt; INSERT INTO cus_info (id, cus_id, phone_num, nick_name, sex) VALUES(6, '200606011708203560006', '10000000006', '阿文', '0');
Query OK, 1 row affected (0.00 sec)
-- 4. 再次select验证insert是否成功
mysql&gt; select * from cus_info where id &gt; 3 and id &lt; 8;
+----+-----------------------+-------------+-----------+-----+
| id | cus_id                | phone_num   | nick_name | sex |
+----+-----------------------+-------------+-----------+-----+
|5 | 200606011708203560005 | 10000000005 | 王      | 0   |
|6 | 200606011708203560006 | 10000000006 | 阿文      | 0   |
|7 | 200606011708203560007 | 10000000007 | 赵      | 1   |
+----+-----------------------+-------------+-----------+-----+
3 rows in set (0.00 sec)</pre></div>
<p>我们再次来看 performance_schema.data_locks 锁信息,可以看到<span><strong>事务2(事务编号为20313)只有【1条】表级别的 IX锁(意向排它锁),并没有对 id = 6 的记录加任何锁(</strong></span><span><strong>实际上,在MySQL的内存中,也就是在 Buffer Pool(缓冲池)的 数据页(页是MySQL中内存和磁盘进行数据交互的基本单位,页分为数据页、undo log页、redo log页等等)上有一条 id=6的记录,并且该记录有一个</strong></span><span><strong>【隐藏列 trx_id(事务编号)】</strong></span><span><strong>,取值为 20313</strong></span><span><strong>)</strong></span>。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183559.png" /></p>
<p><strong>3)、再回到事务1</strong>,执行 普通select 与 update操作(这里我们就更新 事务2插入的 id=6 的新纪录)。</p>
<p>① 先执行普通的 select语句,可以得出结论:事务1确实看不到事务2刚刚插入的id=6的新纪录(因为事务还没有commit,RC级别下,一个事务不会读取到另一个事物未提交的数据);</p>
<p>② 看是看不到(因为事务隔离级别是 RC,读已提交),但是更新操作却会阻塞,直到等待超时。</p>
<div class="jb51code"><pre class="brush:sql;">-- 1. 先执行普通的 select语句,可以得出结论:事务1确实看不到事务2刚刚插入的id=6的新纪录(因为事务还没有commit)
mysql&gt; select * from cus_info where id &gt; 3 and id &lt; 8;
+----+-----------------------+-------------+-----------+-----+
| id | cus_id                | phone_num   | nick_name | sex |
+----+-----------------------+-------------+-----------+-----+
|5 | 200606011708203560005 | 10000000005 | 王      | 0   |
|7 | 200606011708203560007 | 10000000007 | 赵      | 1   |
+----+-----------------------+-------------+-----------+-----+
2 rows in set (0.00 sec)
-- 2. 看是看不到(因为事务隔离级别是 RC,读已提交),但是更新操作却会阻塞,直到等待超时。
mysql&gt; update cus_info set sex=1 where id=6;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction</pre></div>
<p>我们 <strong>在update语句报错(报出 Lock wait timeout)</strong><span><strong>之前</strong></span> 再来查看锁信息,可以看到:</p>
<p>① 事务2给 id = 6 的记录 加了 行级排它锁(X锁,不是Gap锁);</p>
<p>② 事务1的update语句因为要获取 事务2持有的锁,所以进入 waiting(等待状态)。</p>
<p><strong>之所以会这样,<span>是因为 insert语句 一开始给记录加的是【隐式X锁】,当update执行的时候,它会去表的 主键索引 对应的 B+树 去搜索,发现 id=6 的记录的 隐藏列trx_id=20313(事务2的事务编号),并且事务编号为20313的事务处于活跃状态(即,事务没有提交,information_schema.INNODB_TRX表中 trx_id=20313 的 trx_state(事务状态)为 running)</span></strong>,这个时候就会给 performance_schema.data_locks 添加两条记录(即①、②)。</p>
<p><span><strong>处于等待状态的锁</strong></span>:<strong><u>要么在等待超时后死亡;要么在超时前事务2提交成功后获取到锁</u></strong>。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183436.jpg" /></p>
<p><span><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个事务对新插入的记录可以不显式的加锁,但是由于【事务id】的存在,相当于加了一个【隐式锁】。其他事务对这条记录加S锁或者X锁时,由于隐式锁的存在,会先帮助当前事务生成一把锁,然后自己再生成一把锁并进入等待状态</strong></span>。</p>
<p class="maodian"><a name="_lab2_1_1"></a></p><h3>2.2 RR级别下的验证</h3>
<p>修改事务隔离级别:</p>
<div class="jb51code"><pre class="brush:sql;">-- 1. 设置事务隔离级别为:可重复读
mysql&gt; set transaction_isolation = 'REPEATABLE-READ';
Query OK, 0 rows affected (0.00 sec)
-- 2. 查看设置是否成功
mysql&gt; show variables like '%isolation%';
+-----------------------+-----------------+
| Variable_name         | Value         |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)</pre></div>
<p><strong>表数据如下</strong>:id(1, 2, 3, 5, 7, 8)</p>
<p class="maodian"><a name="_label3_1_1_2"></a></p><h4>2.2.1 共享锁(S锁)</h4>
<div class="jb51code"><pre class="brush:sql;">-- 1. 开启事务
mysql&gt; start transaction;
Query OK, 0 rows affected (0.00 sec)
-- 2. 共享锁,select...for share
mysql&gt; select * from cus_info where id &gt; 2 and id &lt; 7 for share;
+----+-----------------------+-------------+-----------+-----+
| id | cus_id                | phone_num   | nick_name | sex |
+----+-----------------------+-------------+-----------+-----+
|3 | 200606011708203560003 | 10000000003 | 默默      | 0   |
|5 | 200606011708203560005 | 10000000005 | 王      | 0   |
+----+-----------------------+-------------+-----------+-----+
2 rows in set (0.00 sec)</pre></div>
<p><strong>查看锁信息</strong>:performance_schema.data_locks</p>
<p>可以看到:</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; ① 给表cus_info加了 表级别的IS锁(意向共享锁)。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;② 加 Next-key Lock(临键锁,记录锁 + 间隙锁),给区间(2, 7)和 记录7 加锁。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183564.jpg" /></p>
<div class="jb51code"><pre class="brush:sql;">-- 测试完后提交或回滚事务
mysql&gt; rollback; -- 或者 commit
Query OK, 0 rows affected (0.00 sec)</pre></div>
<p class="maodian"><a name="_label3_1_1_3"></a></p><h4>2.2.2 排它锁(X锁🔒)</h4>
<h5>1. Update操作</h5>
<div class="jb51code"><pre class="brush:sql;">-- 1. 开启事务
mysql&gt; start transaction;
Query OK, 0 rows affected (0.00 sec)
-- 2. 更新
mysql&gt; update cus_info set sex=1 where id=5;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1Changed: 1Warnings: 0</pre></div>
<p><strong>查看锁信息</strong>:performance_schema.data_locks。</p>
<p>注意看,这里加的行级锁为:X锁(排它锁)、not gap(不是gap锁)。<span><strong><span>唯一索引的等值查询(包括主键索引、唯一二级索引),Next-Key锁会退化为记录锁</span></strong></span>。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183570.png" /></p>
<div class="jb51code"><pre class="brush:sql;">-- 3. 根据 phone_num(唯一索引)更新
mysql&gt; update cus_info set sex=1 where phone_num='10000000005';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1Changed: 1Warnings: 0</pre></div>
<p><strong>再次查看锁信息</strong>:performance_schema.data_locks。注意看 index_name:uk_pn、primary</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183589.png" /></p>
<div class="jb51code"><pre class="brush:sql;">-- 4. 更新区间 (3, 8)
mysql&gt; update cus_info set sex=0 where id&gt;3 and id&lt;8;
Query OK, 1 row affected (0.00 sec)
Rows matched: 2Changed: 1Warnings: 0</pre></div>
<p><strong>再次查看锁信息</strong>:performance_schema.data_locks。这里又是对 (3, 8] 这个区间加 Next-Key Lock(临键锁,记录锁 + 间隙锁)。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183569.png" /></p>
<h5>2. Delete操作</h5>
<div class="jb51code"><pre class="brush:sql;">mysql&gt; delete from cus_info where id=3;
Query OK, 1 row affected (0.00 sec)</pre></div>
<p><strong>查看锁信息</strong>:performance_schema.data_locks</p>
<p>注意看,这里加的行级锁为:X锁(排它锁)、not gap(不是gap锁)。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183565.png" /></p>
<div class="jb51code"><pre class="brush:sql;">-- 为了不影响下面的 select ... for update; 这里我们先回滚事务
mysql&gt; rollback; -- 或者 commit
Query OK, 0 rows affected (0.00 sec)</pre></div>
<h5>3. RR级别Next-Key锁验证</h5>
<p><strong>1)、开启事务1</strong>,并执行 select...for update 操作:</p>
<div class="jb51code"><pre class="brush:sql;">mysql&gt; start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql&gt; select * from cus_info where id &gt; 3 and id &lt; 8 for update;
+----+-----------------------+-------------+-----------+-----+
| id | cus_id                | phone_num   | nick_name | sex |
+----+-----------------------+-------------+-----------+-----+
|5 | 200606011708203560005 | 10000000005 | 王      | 0   |
|7 | 200606011708203560007 | 10000000007 | 赵      | 1   |
+----+-----------------------+-------------+-----------+-----+
2 rows in set (0.00 sec)</pre></div>
<p><strong>查看锁信息</strong>:performance_schema.data_locks。给区间(3, 8)和 记录8 加锁,即给区间 (3, 8] 加了锁。事务1的编号为20320</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183545.png" /></p>
<p><strong>2)、开启事务2</strong>,执行 insert 操作,可以看到 insert 失败了,说明事务1确实对(3, 8] 这个区间范围本身加了 gap锁+记录锁。</p>
<div class="jb51code"><pre class="brush:sql;">-- 1. 开启事务2
mysql&gt; start transaction;
Query OK, 0 rows affected (0.00 sec)
-- 2. insert前先执行 普通select查询看看
mysql&gt; select * from cus_info where id &gt; 3 and id &lt; 8;
+----+-----------------------+-------------+-----------+-----+
| id | cus_id                | phone_num   | nick_name | sex |
+----+-----------------------+-------------+-----------+-----+
|5 | 200606011708203560005 | 10000000005 | 王      | 0   |
|7 | 200606011708203560007 | 10000000007 | 赵      | 1   |
+----+-----------------------+-------------+-----------+-----+
2 rows in set (0.00 sec)
-- 3. insert id=6的记录 失败,因为事务1给 (3, 8] 区间加了 gap锁+记录锁。
mysql&gt; INSERT INTO cus_info (id, cus_id, phone_num, nick_name, sex) VALUES(6, '200606011708203560006', '10000000006', '阿文', '0');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction</pre></div>
<p>我们 <strong>在insert语句报错(报出 Lock wait timeout)</strong><span><strong>之前</strong></span> 再来查看锁信息,可以看到:事务2(事务编号为20321)生成的行锁为:X锁(排它锁)、Gap(间隙锁)、insert intention(插入意向锁),并处于 waiting 状态。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122911183553.png" /></p>
頁: [1]
查看完整版本: MySQL查看事务与锁的操作示例小结