欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于更新SQL语句理解MySQL锁定详解

程序员文章站 2023-11-28 08:22:46
前言 mysql数据库锁是实现数据一致性,解决并发问题的重要手段。数据库是一个多用户共享的资源,当出现并发的时候,就会导致出现各种各样奇怪的问题,就像程序代码一样,出现多...

前言

mysql数据库锁是实现数据一致性,解决并发问题的重要手段。数据库是一个多用户共享的资源,当出现并发的时候,就会导致出现各种各样奇怪的问题,就像程序代码一样,出现多线程并发的时候,如果不做特殊控制的话,就会出现意外的事情,比如“脏“数据、修改丢失等问题。所以数据库并发需要使用事务来控制,事务并发问题需要数据库锁来控制,所以数据库锁是跟并发控制和事务联系在一起的。

本文主要描述基于更新sql语句来理解mysql锁定。下面话不多说了,来一起看看详细的介绍吧

一、构造环境

(root@localhost) [user]> show variables like 'version';
+---------------+------------+
| variable_name | value |
+---------------+------------+
| version | 5.7.23-log |
+---------------+------------+

(root@localhost) [user]> desc t1;
+-------------+--------------+------+-----+---------+----------------+
| field | type | null | key | default | extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | no | pri | null | auto_increment |
| n | int(11) | yes | | null | |
| table_name | varchar(64) | yes | | null | |
| column_name | varchar(64) | yes | | null | |
| pad | varchar(100) | yes | | null | |
+-------------+--------------+------+-----+---------+----------------+

(root@localhost) [user]> select count(*) from t1;
+----------+
| count(*) |
+----------+
| 3406 |
+----------+

(root@localhost) [user]> create unique index idx_t1_pad on t1(pad);
query ok, 0 rows affected (0.35 sec)
records: 0 duplicates: 0 warnings: 0

(root@localhost) [user]> create index idx_t1_n on t1(n);
query ok, 0 rows affected (0.03 sec)
records: 0 duplicates: 0 warnings: 0
(root@localhost) [user]> show index from t1;
+-------+------------+------------+--------------+-------------+-----------+-------------+------+------------+
| table | non_unique | key_name | seq_in_index | column_name | collation | cardinality | null | index_type |
+-------+------------+------------+--------------+-------------+-----------+-------------+------+------------+
| t1 | 0 | primary | 1 | id | a | 3462 | | btree |
| t1 | 0 | idx_t1_pad | 1 | pad | a | 3406 | yes | btree |
| t1 | 1 | idx_t1_n | 1 | n | a | 12 | yes | btree |
+-------+------------+------------+--------------+-------------+-----------+-------------+------+------------+
select 'leshami' author,'http://blog.csdn.net/leshami' blog;
+---------+------------------------------+
| author | blog |
+---------+------------------------------+
| leshami | http://blog.csdn.net/leshami |
+---------+------------------------------+

二、基于主键更新

(root@localhost) [user]> start transaction;
query ok, 0 rows affected (0.00 sec)

(root@localhost) [user]> update t1 set table_name='t1' where id=1299;
query ok, 1 row affected (0.00 sec)
rows matched: 1 changed: 1 warnings: 0

select trx_id,
 trx_state,
 trx_started,
 trx_mysql_thread_id,
 trx_tables_locked,
 trx_rows_locked,
 trx_rows_modified,
 trx_isolation_level
from information_schema.innodb_trx \g

-- 从下面的结果可知,trx_rows_locked,一行被锁定 
*************************** 1. row ***************************
 trx_id: 6349647
 trx_state: running
 trx_started: 2018-11-06 16:54:12
trx_mysql_thread_id: 2
 trx_tables_locked: 1
 trx_rows_locked: 1
 trx_rows_modified: 1
trx_isolation_level: repeatable read 

(root@localhost) [user]> rollback;
query ok, 0 rows affected (0.01 sec)

三、基于二级唯一索引

(root@localhost) [user]> start transaction;
query ok, 0 rows affected (0.00 sec)

(root@localhost) [user]> update t1 set table_name='t2' where pad='4f39e2a03df3ab94b9f6a48c4aecdc0b';
query ok, 1 row affected (0.00 sec)
rows matched: 1 changed: 1 warnings: 0

select trx_id,
 trx_state,
 trx_started,
 trx_mysql_thread_id,
 trx_tables_locked,
 trx_rows_locked,
 trx_rows_modified,
 trx_isolation_level
from information_schema.innodb_trx \g

-- 从下面的查询结果可知,trx_rows_locked,2行被锁定
*************************** 1. row ***************************
 trx_id: 6349649
 trx_state: running
 trx_started: 2018-11-06 16:55:22
trx_mysql_thread_id: 2
 trx_tables_locked: 1
 trx_rows_locked: 2
 trx_rows_modified: 1
trx_isolation_level: repeatable read 

(root@localhost) [user]> rollback;
query ok, 0 rows affected (0.00 sec)

三、基于二级非唯一索引

(root@localhost) [user]> start transaction;
query ok, 0 rows affected (0.00 sec)

(root@localhost) [user]> update t1 set table_name='t3' where n=8;
query ok, 350 rows affected (0.01 sec)
rows matched: 351 changed: 351 warnings: 0

select trx_id,
 trx_state,
 trx_started,
 trx_mysql_thread_id,
 trx_tables_locked,
 trx_rows_locked,
 trx_rows_modified,
 trx_isolation_level
from information_schema.innodb_trx \g
 
--从下面的查询结果可知,703行被锁定
*************************** 1. row ***************************
  trx_id: 6349672
  trx_state: running
 trx_started: 2018-11-06 17:06:53
trx_mysql_thread_id: 2
 trx_tables_locked: 1
 trx_rows_locked: 703
 trx_rows_modified: 351
trx_isolation_level: repeatable read

(root@localhost) [user]> rollback;
query ok, 0 rows affected (0.00 sec)

四、无索引更新

(root@localhost) [user]> start transaction;
query ok, 0 rows affected (0.00 sec)

(root@localhost) [user]> update t1 set table_name='t4' where column_name='id';
query ok, 26 rows affected (0.00 sec)
rows matched: 26 changed: 26 warnings: 0

select trx_id,
 trx_state,
 trx_started,
 trx_mysql_thread_id,
 trx_tables_locked,
 trx_rows_locked,
 trx_rows_modified,
 trx_isolation_level
from information_schema.innodb_trx \g

-- 从下面的查询结果可知,trx_rows_locked,3429行被锁定,而被更新的仅仅为26行
-- 而且这个结果超出了表上的总行数3406
*************************** 1. row ***************************
  trx_id: 6349674
  trx_state: running
 trx_started: 2018-11-06 17:09:41
trx_mysql_thread_id: 2
 trx_tables_locked: 1
 trx_rows_locked: 3429
 trx_rows_modified: 26
trx_isolation_level: repeatable read

(root@localhost) [user]> rollback;
query ok, 0 rows affected (0.00 sec)

-- 也可以通过show engine innodb status进行观察

show engine innodb status\g

------------
transactions
------------
trx id counter 6349584
purge done for trx's n:o < 0 undo n:o < 0 state: running but idle
history list length 0
list of transactions for each session:
---transaction 421943222819552, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---transaction 6349583, active 2 sec
2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1


------------
transactions
------------
trx id counter 6349586
purge done for trx's n:o < 6349585 undo n:o < 0 state: running but idle
history list length 1
list of transactions for each session:
---transaction 421943222819552, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---transaction 6349585, active 8 sec
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
mysql thread id 2, os thread handle 140467640694528, query id 29 localhost root

五、锁相关查询sql

1:查看当前的事务

select * from information_schema.innodb_trx;

2:查看当前锁定的事务

select * from information_schema.innodb_locks;

3:查看当前等锁的事务

select * from information_schema.innodb_lock_waits;

select trx_id,
 trx_state,
 trx_started,
 trx_mysql_thread_id thr_id,
 trx_tables_locked tb_lck,
 trx_rows_locked rows_lck,
 trx_rows_modified row_mfy,
 trx_isolation_level is_lvl
from information_schema.innodb_trx;

select r.`trx_id` waiting_trx_id,
 r.`trx_mysql_thread_id` waiting_thread,
 r.`trx_query` waiting_query,
 b.`trx_id` bolcking_trx_id,
 b.`trx_mysql_thread_id` blocking_thread,
 b.`trx_query` block_query
from information_schema.`innodb_lock_waits` w
 inner join information_schema.`innodb_trx` b
 on b.`trx_id` = w.`blocking_trx_id`
 inner join information_schema.`innodb_trx` r
 on r.`trx_id` = w.`requesting_trx_id`;

六、小结

1、mysql表更新时,对记录的锁定根据更新时where谓词条件来确定锁定范围

2、对于聚簇索引过滤,由于索引即数据,因为仅仅锁定更新行,这是由聚簇索引的性质决定的

3、对于非聚簇唯一索引过滤,由于需要回表,因此锁定为唯一索引过滤行数加上回表行数

4、对于非聚簇非唯一索引过滤,涉及到了间隙锁,因此锁定的记录数更多

5、如果过滤条件无任何索引或无法使用到索引,则锁定整张表上所有数据行

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。