【数据库】——MySQL锁

一、MyISAM表锁

1、查询表级锁争用情况

在这里插入图片描述

2、MySQL表级锁的锁模式

MySQL的表级锁有两种模式:表共享读锁和表独占写锁,他们的兼容性如下:
在这里插入图片描述
总结即为读锁共享、独占写锁。
独占写锁的讲解示意图如下:
在这里插入图片描述
读锁共享的讲解示意图如下:
在这里插入图片描述

3、如何添加表锁

(1)一般的,在执行select语句前,会自动给涉及到的所有表加读锁,在执行更新操作(updata,delete,insert)前,会给涉及的表加写锁
(2)@特殊地,一般为了在一定程度模拟事务操作,实现对某一时间点多个表的一致性读取。如下:
在这里插入图片描述
(3)当使用lock table时,不仅需要一次锁定用到的所有表,而且,同一表在SQL语句中出现多少次,就要通过与SQL语句中相同的别名锁定多少次。例子如下:
在这里插入图片描述

4、MyISAM的锁调度

MyISAM存储引擎的读锁和写锁是互斥的,读写操作是串行的。其有写进程先获得锁,即便是读进程先到,写锁也会插入到读锁请求之前。这也是为什么MyISAM不太适合有大量更新操作和查询操作应用的原因。
以下为MyISAM调度行为的调节:

  • 通过指定启动参数low-priority-updatas,使MyISAM引擎默认给与读请求以优先的权利
  • 通过执行命令SET LOW_PRIORITY_UPDATES=1使该链接发出的更新请求优先级降低
  • 通过指定INSERT,UPDATA,DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。

二、InnoDB锁问题

1、获取InnoDB行锁争用情况

可以通过检查InnoDB_row_lock状态变量来分析系统上的行锁争夺情况。
在这里插入图片描述
如果InnoDB_row_lock_waits和InnoDB_row_time_ayg的值比较高,说明锁争用比较严重。
可以通过设置InnoDB Monitors来进一步观察发生锁冲突的表、数据行等,并分析争用的原因。

在这里插入图片描述

2、InnoDB 的行锁模式及加锁方式

(1)InnoDB 实现了以下两种类型的锁:

  • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁

  • 排他锁(X):允许排它锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
    在这里插入图片描述
    (2)加锁方式
    意向锁是InnoDB自动加的,不需要用户干预。对于update、delete和insert语句,InnoDB会自动给涉及数据集加排他锁。对于普通select语句,InnoDB不会加任何锁。
    可以通过以下语句显示给记录集加共享锁和排它锁

  • 共享锁:select * from table_name where … lock in share mode

  • 排它锁:select * from table_name where …for updata.
    共享锁在这里插入图片描述
    排它锁:同一行上写锁和写锁不能共存,只对一行数据加锁,对其他数据没有影响
    在这里插入图片描述

3、InnoDB行锁实现方式

我们都知道对同一行的数据上,可以同时加多个读锁,A链接加读锁,B链接也可加读锁 读锁和读锁共存 写锁和写锁、写锁和读锁不共存。但是有这样一个情况,对A第一行数据加一个读锁,B对第二条数据进行修改,但是链接B阻塞等待,这是为什么呢?
因为在InnoDB中其实也存在表锁,只有索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁

select * from test where id = 1;id是主索引 索引查询
select * from test where name = “zhangsan”;name非索引,非索引查询

注意!!!由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然访问不同行的记录,但是如果使用相同的索引键,会出现锁冲突。

当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外。不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。例子如下:
在这里插入图片描述
在这里插入图片描述

4、间隙锁

(1)举例子来说:假如emp表中只有101条记录,其empid的值分别为1,2,…,100,101,下面的SQL:
select * from emp where empid > 100 for updata;
是一个范围条件的检索,InnnoDB不仅对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录不存在)的“间隙”加锁。
(2)加锁目的

  • 防止幻读,以满足隔离级别的要求
  • 满足其回复和复制的需要

三、其他

1、隔离级别和锁的关系

对于许多SQL,隔离级别越高,InnoDB给记录加的锁就越严格,产生锁冲突的可能性也就越高,从而对并发性事务处理性能的影响也就越大。因此,我们在应用中,应该尽量使用较低的隔离级别,以减少锁争用的几率。

2、InnoDB什么情况下使用表锁

绝大多数情况下都应该使用行级锁,个别特殊事务中,可以考虑使用表级锁

  • 第一种情况:事务需要更新大部分或全部数据,表又比较大
  • 事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚

3、死锁

意向锁就是为了防止死锁的出现
(1)MyISAM不会出现死锁,但是InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,可就决定了InnoDB中发生死锁的可能。

(2) 发生死锁后的解决方法

  • 一般的,InnoDB能够自动检测,并使一个事务释放并回退,另一个事务获得锁,继续完成事务。
  • 涉及外部锁和表锁的情况下,InnoDB不能完全自动检测到死锁,这时需要通过设置锁等待超时参数innodb_lock_wait_timeout来解决。

(3)如何避免死锁

  • 不同的程序并发存取多个表,应尽量约定以相同的顺序来访问表
  • 在程序以批量方式处理数据的时候,如果事先对数据排序,保证每个线程按固定的顺序来处理记录
  • 在事务中,如果要更新记录,应该直接申请足够级别的锁,即排他锁,而不应该先申请共享锁,更新时再申请排他锁。
  • 尽量使用较低的隔离级别
  • 精心设计索引,并尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会
  • 选择合理的事务大小,小事务发生锁冲突的几率更小

4、悲观锁和乐观锁

悲观锁:操作人员认为每个操作都可能出现错误,所以会提前加锁,保证数据都正确 比如说:MyISAM的表锁 InnoDB中的行锁
乐观锁:他认为每件事都可能成功,出现问题的时候才加锁,保证数据的正常进行,一般添加版本标识来实现

发布了62 篇原创文章 · 获赞 7 · 访问量 2554

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/104909892