代码改变世界

Mysql 锁

2020-06-26 12:12  Tony、  阅读(264)  评论(0编辑  收藏  举报

锁类型

  共享锁(S)

  排它锁(X)

  意向共享锁(IS)

  意向排他锁(IX)

锁的算法

  记录锁(Record Locks)

  间隙锁(Gap Locks)

  临建锁(Next-key Locks)

 

共享锁(S):又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改;

加锁释锁方式:

set session autocommit = OFF;
select * from users WHERE id=1 LOCK IN SHARE MODE;
commit/rollback

排它锁(X):又称为写锁,简称X锁,排他锁不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的锁(共享锁、排他锁),只有该获取了排他锁的事务是可以对数据行进行读取和修改,(其他事 务要读取数据可来自于快照)

加锁释锁方式: 

set session autocommit=OFF;
SELECT * FROM table_ name WHERE id=1 FOR UPDATE;
commit/rollback;

   delete / update / insert默认加上X锁

意向共享锁(IS)和意向排它锁(IX)统称为意向锁(IS、IX)

  意向锁是InnoDB数据操作之前自动加的,不需要用户干预。当用户给行添加S或者X锁的时候,会自动的给表加上IS和IX锁。

意向锁主要是用来标识该表是否已经有行被加上锁了,如果有事务试图给表加上表锁(lock tables xx read/write ),就会先看改表是否有共享锁,如果有就不能加锁,主要是为了提高效率,如果没有这个标识,就需要遍历所有的行,看有没有锁,会浪费很多的资源,降低效率。

innodb-行锁到底锁了什么?

   行锁最终都是通过锁定索引来实现的,如果锁定行的时候没有命中索引,就会用表锁来锁定。

为什么锁住辅助索引 主键索引也会被锁住?

  因为用辅助索引查询数据的时候有个回表的操作,所以也会把主键索引锁住,同时也可以说明,对于同一行数据,如果一个索引被锁住了,其他的索引页相当于被锁住了,因为主键索引最终会被锁住,所以其他索引在回表的时候都会被锁住。

  

 

 

 

 

记录锁(Record)&间隙锁(Gap)&临键锁(Next-key):这三类锁只是针对共享锁和排他锁的算法

记录锁(Record locks):

  锁住具体的索引项,当sq|执行按照唯一-性(Primarykey、Uniquekey)索引进行数据的检索时,查询条件等值匹配且查询的数据是存在,这时SQL语句加上的锁即为记录锁Record locks, 锁住具体的索引项。

         

 

 如果把事务的隔离级别降级为读提交(Read Committed, RC),间隙锁则会自动失效。

间隙锁(Gap locks)

  锁住数据不存在的区间(左开右开),当sql执行按照索引进行数据的检索时,查询条件的数据不存在,这时SQL语句加上的锁即为Gap locks, 锁住索引不存在的区间(左开右开)

  

 

 如果把事务的隔离级别降级为读提交(Read Committed, RC)或者未提交读(Read Uncommited),间隙锁 则会自动失效。

临键锁(Next-key locks)

  锁住记录+区间(左开右闭),当sq|执行按照索引进行数据的检索时,查询条件为范围查找(betweenand、<、>等)并有数据命中则此时SQL语句加上的锁为Next-key locks, 锁住索引的记录+区间(左开右闭)

  

 如果把事务的隔离级别降级为读提交(Read Committed, RC)或者未提交读(Read Uncommited),临键锁 则会自动失效。

 

 

不同的事物隔离级别中同样的锁 粒度是不同的

未提交:即使加了锁 也会失效

提交读:只有记录锁

可重复读:记录锁 间隙锁 临建锁

串行化:和可重复读相同

 

查看mysql锁详解

1 打开锁监控
set GLOBAL innodb_status_output=ON;
set GLOBAL innodb_status_output_locks=ON;

2 查询命令

show engine innodb status\G

3 锁介绍

记录锁:lock_mode X locks rec but not gap

间隙锁:lock_mode X locks gap before rec

临建锁:lock_mode X

意向排它锁:TABLE LOCK table `test`.`t4` trx id 1956 lock mode IX

意向共享锁:TABLE LOCK table `test`.`t4` trx id 1956 lock mode IS

表排他锁:TABLE LOCK table `test`.`t4` trx id 1957 lock mode X

表共享锁:TABLE LOCK table `test`.`t4` trx id 1957 lock mode S

 

 

网址:https://www.jianshu.com/p/7004f7571427

 

 

 

 

 

MVCC是什么?

  Multiversion concurrency control多版本并发控制),并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理。以达到用来避免写操作的堵塞,从而引发读操作的并发问题。

  MVCC只适用于select查询,是基于undo log来做的  在数据库中每行数据会有两个隐藏的字段 事物Id(db_trx_id)和回滚地址(db_roll_pt),事物在对行数据进行操作的时候,在undo log中会按照事物的提交顺序形成一个版本链,每一个版本中都会记录db_trx_id ,db_roll_id,以及delete flag 标识。mvcc 就是基于这些版本来查询数据的。

 

 

 

 

 

 

 

 

  在RR隔离基本下 read-view 是在事物的第一个read操作时建立的
  在RC隔离级别下 事务每次read操作都会建立一个read-view

 

 如何尽可能避免死锁?

  1 合理的设计索引,区分度高的列放到组合索引前面,使业务 SQL 尽可能通过索引定位更少的行,减少锁竞争。

  2 调整业务逻辑 SQL 执行顺序, 避免 update/delete 长时间持有锁的 SQL 在事务前面。

  3 避免大事务,尽量将大事务拆成多个小事务来处理,小事务发生锁冲突的几率也更小。

  4 以固定的顺序访问表和行。比如两个更新数据的事务,事务 A 更新数据的顺序为 1,2;事务 B 更新数据的顺序为 2,1。这样更可能会造成死锁。

  5 在并发比较高的系统中,不要显式加锁,特别是是在事务里显式加锁。如 select … for update 语句,如果是在事务里(运行了 start transaction 或设置了autocommit 等于0),那么就会锁定所查找到的记录。

  6 尽量按主键/索引去查找记录,范围查找增加了锁冲突的可能性,也不要利用数据库做一些额外额度计算工作。比如有的程序会用到 “select … where … order by rand();”这样的语句,由于类似这样的语句用不到索引,因此将导致整个表的数据都被锁住。

  7 优化 SQL 和表设计,减少同时占用太多资源的情况。比如说,减少连接的表,将复杂 SQL 分解为多个简单的 SQL。

参考:https://mp.weixin.qq.com/s/y_f2qrZvZe_F4_HPnwVjOw