mysql手册12_锁机制

mysql手册12_锁机制


锁是协调多个线程并发访问某一资源的机制(避免资源的争抢)

锁的分类

  • 以对数据库的操作粒度划分:表锁(操作时锁定整个表)、行锁(锁定当前行)
  • 以对数据库的操作类型划分:读锁(共享锁)、写锁(排他锁)

共享锁:多个事务可并发读取数据,但任何事务都不可获取数据的排它锁(写),除非已释放所有共享锁

排它锁:某个事务获得了排它锁,其他事务不能读取也不能修改


各存储引擎对锁的支持情况:

存储引擎 表级锁 行级锁 页面锁
MyISAM 支持 不支持 不支持
InnoDB 支持 支持 不支持
MEMORY 支持 不支持 不支持
BDB 支持 不支持 支持

3种锁的特性:

锁类型 特点
表级锁 偏向MyISAM存储引擎,开销小,加锁快,不会出现死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低
行级锁 偏向InnoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突的概率最低,并发度最高
页面锁 开销和加锁时间中等,会出现死锁,锁定粒度中等,并发度一般

MyISAM存储引擎的表锁

在执行查询语句前,MyISAM会 自动 给涉及的表加上 读锁
在执行更新操作前,MyISAM会 自动 给涉及的表加上 写锁

对 MyISAM 表的读操作,不会阻塞其他事务对同一个表的读操作,但会阻塞其他事务对该表的写操作
对 MyISAM 表的写操作,则会阻塞其他事务对同一表的读和写操作

所以 MyISAM 不适合做以写为主的表的存储引擎

扫描二维码关注公众号,回复: 11712555 查看本文章
列举当前状态在表缓存中当前被打开的表,In_use不等于0表示该表正在被锁定
show open tables

+--------------------+---------------------------+--------+-------------+
| Database           | Table                     | In_use | Name_locked |
+--------------------+---------------------------+--------+-------------+
| mysql              | default_roles             |      0 |           0 |
| mysql              | check_constraints         |      0 |           0 |
| mysql              | slave_master_info         |      0 |           0 |
................
................
................
查看表锁的情况
show status like 'Table_locks%';

+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Table_locks_immediate | 9     |
| Table_locks_waited    | 0     |
+-----------------------+-------+

Table_locks_immediate 表示能够立即获得表级锁的次数
Table_locks_waited 表示需要等待获取表锁的次数,该值较高说明存在严重的表级锁的争用情况

InnoDB存储引擎的行锁

InnoDB 与 MyISAM 的最大不同有两点:支持事务、采用行级锁

并发事务带来的问题

问题 含义
丢失更新 多个事务操作同一行数据时,后提交的事务修改的值会覆盖前面提交的事务修改的值
脏读 一个事务访问到了另一个事务还没有提交的数据
不可重复读 同一事务中执行了两次相同的查询,得到的结果不一致
幻读 事务在插入已经检查过不存在的记录时,惊奇的发现这些数据已经存在了

使用事务的隔离级别来解决以上问题

隔离级别 丢失更新 脏读 不可重复读 幻读
Read uncommitted X Y Y Y
Read committed X X Y Y
Repeatable read (默认) X X X Y
Serializable X X X X

注:当 Where 查询条件中的字段没有索引,或者索引失效时,InnoDB 默认的行锁更新操作将变为表锁!应该尽量避免!

间隙锁
间隙锁(Gap Lock)是Innodb在可重复读提交下为了解决幻读问题时引入的锁机制,在更新操作中如果进行了范围查询,此时的行级锁将无法满足要求,需要对一定范围的行数据进行加锁

举例:数据库中存在id为1,3,4,5,6 的数据,缺少id为2的数据

A事务执行以下更新操作,此时范围 id<5 的行数据将被加锁

update t_user set name = "zhangsan" where id < 5

同时B事务执行以下 insert 语句,此时B事务将进入阻塞状态,直至A事务提交

insert into t_user values(2,'lisi');

注:尽量缩小范围区间以避免间隙锁


查看InnoDB的行锁争用情况:

show status like 'innodb_row_lock%';

+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0     |
| Innodb_row_lock_time          | 0     |
| Innodb_row_lock_time_avg      | 0     |
| Innodb_row_lock_time_max      | 0     |
| Innodb_row_lock_waits         | 0     |
+-------------------------------+-------+

Innodb_row_lock_current_waits 	当前正在等待行锁的数量
Innodb_row_lock_time 			锁定的总时长
Innodb_row_lock_time_avg 		锁定的平均时长
Innodb_row_lock_time_max 		锁定的最大时长
Innodb_row_lock_waits			系统启动至今总共等待的次数

总结:

虽然 InnoDB 在锁机制上的性能损耗比 MyISAM 高,但在整体并发处理能力方面远远优于 MyISAM

优化建议:

  • 尽可能让所有数据的检索通过索引完成,以避免行锁升级为表锁
  • 合理涉及索引,尽量缩小锁的范围
  • 尽可能减少索引条件和索引范围,避免间隙锁
  • 尽量控制事务大小,减少锁定的资源量和锁定的时间长度
  • 尽可能使用低级别的事务隔离(在满足业务需求的前提下)

猜你喜欢

转载自blog.csdn.net/BLU_111/article/details/108286063