《MySQL技术内幕:InnoDB存储引擎》6. 锁

本文深入解析MySQL中的锁机制,涵盖latch与lock的区别、锁的类型(共享锁、排他锁、意向锁)、一致性非锁定读与锁定读、自增长与锁、外键与锁、事务隔离级别对锁的影响及常见问题解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


MySQL中的锁是为了解决共享资源存在的并发访问问题,不止是表数据,包括操作缓存池
中的LRU列表都会有锁的介入。

1. latch和lock

名称区别
latch轻量级锁,锁定的时间短,用来保证临界资源,但没有死锁的检测;分为mutex(互斥锁)和rwlock(读写锁)
lock锁定数据库中的对象:表,页,行;lock对象仅在commit后rollback后释放;有死锁机制
mysql> show engine innodb mutex;
+--------+-----------------------------+-----------+
| Type   | Name                        | Status    |
+--------+-----------------------------+-----------+
| InnoDB | rwlock: dict0dict.cc:1183   | waits=24  |
| InnoDB | rwlock: log0log.cc:838      | waits=105 |
| InnoDB | sum rwlock: buf0buf.cc:1460 | waits=7   |
+--------+-----------------------------+-----------+
3 rows in set (0.03 sec)

2. 锁lock

2.1 锁的类型

名称区别
共享锁(S Lock)允许事务读取一行数据 ;S锁和S锁之间才兼容:兼容即不会阻塞等待
排他锁(X Lock)允许事务删除或更新一行数据;X锁和其他都不兼容

若是有一个线程通过共享锁锁住了某一行数据,则要在这一行上加上S锁则能成功,而加上X锁则不行,需要
等待S锁释放,因为X锁和其他锁都不兼容

意向锁:想对/意向某个层次粒度的对象加锁;若是想对某页记录加上X锁,则需先对数据库、表、页
加上意向锁IX,最后才加上X锁

名称区别
意向共享锁(IS Lock)事务想要获得某几行的共享锁
意向排他锁(IX Lock)事务想要获得某几行的排他锁

3. 一致性非锁定读:快照数据

概念:读取的行被其他session控制并在执行update或delete操作时,读取操作不会等待锁的释放,而是读取行的一个快照数据。
快照数据:该行之前的历史版本数据,读取快照数据不需要加锁,因为没有事务需要对历史数据进行修改操作
隔离级别不同,读取的快照数据也不同
	read committed:读取最新一份快照数据
	repeatable read(可重复读):读取该事务开始时的行数据版本
session Asession B
begin
select * from table where id = 1
begin
update table set id = 2 where id = 1
select * from table where id = 1
commit
select * from table where id = 1
commit

read committed:在session B commit后,查到的是最新数据,查询不到id = 1数据

repeatable read:读取该事务开始时的数据版本,则及时session B commit,还能查到id = 1的数据

需实验一下

3.1 通过如下三个表可观察锁的情况

mysql> select * from information_schema.innodb_locks
    -> ;
Empty set (0.00 sec)
mysql> select * from information_schema.innodb_lock_waits;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 4370              | 4370:29:3:2       | 4368            | 4368:29:3:2      |
+-------------------+-------------------+-----------------+------------------+
1 row in set, 1 warning (0.00 sec)

mysql> select * from information_schema.innodb_locks;
+-------------+-------------+-----------+-----------+--------------------+-----------------+------------+-----------+----------+----------------+
| lock_id     | lock_trx_id | lock_mode | lock_type | lock_table         | lock_index      | lock_space | lock_page | lock_rec | lock_data      |
+-------------+-------------+-----------+-----------+--------------------+-----------------+------------+-----------+----------+----------------+
| 4370:29:3:2 | 4370        | X         | RECORD    | `test`.`lock_test` | GEN_CLUST_INDEX |         29 |         3 |        2 | 0x000000000200 |
| 4368:29:3:2 | 4368        | X         | RECORD    | `test`.`lock_test` | GEN_CLUST_INDEX |         29 |         3 |        2 | 0x000000000200 |
+-------------+-------------+-----------+-----------+--------------------+-----------------+------------+-----------+----------+----------------+
2 rows in set, 1 warning (0.00 sec)


3.2 多版本并发:MVVC

InnoDB默认的读取是不会获得和等待锁,读取的是快照数据,即该行数据的历史版本
,通过undo实现,而一行数据的历史记录有多个版本,这种技术就是多版本技术,由此
带来的并发是多版本并发控制(Multi Version Concurrency Control,MVCC)

4. 一致性锁定读:支持如下两种

select ... from update:加X锁
select ... lock in share mode:加S锁

一致性非锁定读
​ 也是支持上诉两种,需要加上begin,start transaction或者set autocommit = 0;

5. 自增长和锁

  • 自增长有一个计数器:select MAX(auto_inc_col) from t for update;
  • auto-inc locking:
    • 优点:特殊的表锁设计,锁不是在一个事务完成后才释放,而是自增插入的sql完成后立即释放(提高插入性能)
    • 缺点:大数据插入性能低,每一个插入都得等待前一个完成
  • innodb_autoinc_lock_mode:控制自增长模式,比auto-inc locking性能好
  • InnoDB:自增长值的列必须的索引且是索引的第一个列

6. 外键和锁

  • innobd会自动对外键加一个索引
  • 外键值的插入或更新,需要先select父表,使用的是一致性锁定读,select...lock in share mode:性能低,父子表耦合会出现阻塞等

7. 修改事务隔离级别

SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;	

set session transaction_isolation = 'read-committed';
set global transaction_isolation = 'read-committed';

8. 问题:for update后其他update语句会被阻塞延迟执行

8.1 事务1:加排他锁(悲观锁)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t where id = 1 for update;
+----+------+---------------------+---------------------+
| id | name | created_time        | updated_time        |
+----+------+---------------------+---------------------+
|  1 | A    | 2018-11-06 11:57:01 | 2018-11-06 11:57:01 |
+----+------+---------------------+---------------------+
1 row in set (0.00 sec)

mysql> update t set name = 'Q' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t; -- id为1的那么是P,被其他事务修改了
+----+------+---------------------+---------------------+
| id | name | created_time        | updated_time        |
+----+------+---------------------+---------------------+
|  1 | P    | 2018-11-06 11:57:01 | 2018-11-06 11:57:01 |
|  2 | N    | 2018-11-06 11:58:38 | 2018-11-06 11:58:38 |
+----+------+---------------------+---------------------+
2 rows in set (0.00 sec)

8.2 事务2:update已有锁的行,会被阻塞,等其他事务释放锁后才能执行
mysql> update t set name = 'P' where id = 1;
Query OK, 1 row affected (20.71 sec)
Rows matched: 1  Changed: 1  Warnings: 0
等了 20 秒才执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值