全局锁就是对整个数据库实例加锁。MySQL提供了一个加全局读锁的方法,命令是Flush tables with read lock。当需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句
全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都select出来存成文本
但是让整个库都只读,可能出现以下问题:
表锁的语法是 lock tables … read/write。与 FTWRL 类似,可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放。 需要注意,lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。
flyway脚本的 DDL可能拿不到MDL写锁执行失败。 - DML操作需要metadata读锁,DDL操作需要metadata写锁。 - 读锁和写锁之间相互阻塞,即同一个表上的DML和DDL之间互相阻塞。 - 写锁和写锁之间互相阻塞,即两个session不能对表同时做表定义变更,需要串行操作。 - 读锁和读锁之间不会产生阻塞。也就是增删改查不会因为metadata lock产生阻塞,可以并发执行。
MySQL的行锁是在引擎层由各个引擎自己实现的 InnoDB支持行锁,MyISAM不支持行锁
在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。
当出现死锁以后,有两种策略:
如果所有事务都要更新同一行的场景,每个新来的被堵住的线程都要判断会不会由于自己的加入导致死锁,这是一个时间复杂度是O(n)的操作
怎么解决由这种热点行更新导致的性能问题?
解决了mysql RR级别下是幻读的问题。
因为Query执行过程中通过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,也造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害。
间隙锁的出现是为了在innodb的可重复读隔离级别下,解决幻读问题产生的。
间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据;所谓间隙是将数据分为不同区间,对该区间范围进行加锁,区间的规则为左开右闭,比如当数据为1,3,5时,对应的区间为(-∞,1],(1,3],(3,5],(5,+∞];
他这个行锁+间隙锁就组成了next—key lock,innodb在可重复度隔离级别下,采用next-key lock来防止幻读,因此实现了最高的隔离级别。
对于操作的数据是主键索引和普通索引,有不同的加锁规则,如下:
1)、唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁; 2)、普通索引不管是锁住单条,还是多条记录,都会产生间隙锁;
评论