MyISAM存储引擎 中的读写锁


MyISAM存储引擎

InnoDB和MyISAM的最大不同点有两个:

  1. InnoDB支持事务(transaction);MyISAM不支持事务
  2. Innodb 默认采用行锁, MyISAM 是默认采用表锁。加锁可以保证事务的一致性,可谓是有人(锁)的地方,就有江湖(事务)
  3. MyISAM不适合高并发

共享读锁

对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读操作,但会阻塞对同一表的写操作。只有当读锁释放后,才能执行其他进程的写操作。在锁释放前不能读其他表。

 

 

 

独占写锁

对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其他进程的读写操作。在锁释放前不能写其他表。

 

总结:

 

  1. 表锁,读锁会阻塞写,不会阻塞读。而写锁则会把读写都阻塞。
  2. 表锁的加锁/解锁方式:MyISAM 在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作 (UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。

如果用户想要显示的加锁可以使用以下命令:

锁定表:

LOCK TABLES tbl_name {READ | WRITE},[ tbl_name {READ | WRITE},…] 
复制代码

解锁表:

UNLOCK TABLES 
复制代码

在用 LOCK TABLES 给表显式加表锁时,必须同时取得所有涉及到表的锁。 在执行 LOCK TABLES 后,只能访问显式加锁的这些表,不能访问未加锁的表;

如果加的是读锁,那么只能执行查询操作,而不能执行更新操作。

在自动加锁的情况下也基本如此,MyISAM 总是一次获得 SQL 语句所需要的全部锁。这也正是 MyISAM 表不会出现死锁(Deadlock Free)的原因。

对表test_table增加读锁:

LOCK TABLES test_table READ 
UNLOCK test_table
复制代码

对表test_table增加写锁

LOCK TABLES test_table WRITE
UNLOCK test_table
复制代码

当使用 LOCK TABLES 时,不仅需要一次锁定用到的所有表,而且,同一个表在 SQL 语句中出现多少次,就要通过与 SQL 语句中相同的别名锁定多少次,否则也会出错!

比如如下SQL语句:

select a.first_name,b.first_name, from actor a,actor b where a.first_name = b.first_name;
复制代码

该Sql语句中,actor表以别名的方式出现了两次,分别是a,b,这时如果要在该Sql执行之前加锁就要使用以下Sql:

lock table actor as a read,actor as b read;
复制代码

并发插入

上文说到过 MyISAM 表的读和写是串行的,但这是就总体而言的。在一定条件下,MyISAM表也支持查询和插入操作的并发进行。 MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为0、1或2。

  • 当concurrent_insert设置为0时,不允许并发插入。
  • 当concurrent_insert设置为1时,如果MyISAM表中没有空洞(即表的中间没有被删除的 行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL 的默认设置。
  • 当concurrent_insert设置为2时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。

可以利用MyISAM存储引擎的并发插入特性,来解决应用中对同一表查询和插入的锁争用。

MyISAM的锁调度

前面讲过,MyISAM 存储引擎的读锁和写锁是互斥的,读写操作是串行的。那么,一个进程请求某个 MyISAM 表的读锁,同时另一个进程也请求同一表的写锁,MySQL 如何处理呢?

答案是写进程先获得锁。

不仅如此,即使读请求先到锁等待队列,写请求后到,写锁也会插到读锁请求之前!这是因为 MySQL 认为写请求一般比读请求要重要。这也正是 MyISAM 表不太适合于有大量更新操作和查询操作应用的原因,因为大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。这种情况有时可能会变得非常糟糕!

幸好我们可以通过一些设置来调节 MyISAM 的调度行为。

通过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。

  • 通过执行命令SET LOWPRIORITYUPDATES=1,使该连接发出的更新请求优先级降低。
  • 通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。
  • 另外,MySQL也 供了一种折中的办法来调节读写冲突,即给系统参数max_write_lock_count 设置一个合适的值,当一个表的读锁达到这个值后,MySQL就暂时将写请求的优先级降低, 给读进程一定获得锁的机会。

总结

  • 数据库中的锁从锁定的粒度上分可以分为行级锁、页级锁和表级锁。
  • MySQL的MyISAM引擎支持表级锁。
  • 表级锁分为两种:共享读锁、互斥写锁。这两种锁都是阻塞锁。
  • 可以在读锁上增加读锁,不能在读锁上增加写锁。在写锁上不能增加写锁。
  • 默认情况下,MySql在执行查询语句之前会加读锁,在执行更新语句之前会执行写锁。
  • 如果想要显示的加锁/解锁的花可以使用LOCK TABLES和UNLOCK来进行。
  • 在使用LOCK TABLES之后,在解锁之前,不能操作未加锁的表。
  • 在加锁时,如果显示的指明是要增加读锁,那么在解锁之前,只能进行读操作,不能执行写操作。
  • 如果一次Sql语句要操作的表以别名的方式多次出现,那么就要在加锁时都指明要加锁的表的别名。
  • MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为0、1或2。
  • 由于读锁和写锁互斥,那么在调度过程中,默认情况下,MySql会本着写锁优先的原则。可以通过low-priority-updates来设置。


作者:蒋老湿
链接:https://juejin.im/post/5b82e0196fb9a019f47d1823
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值