mysql高级(四)——锁

表锁(基于MYISAM引擎)

  • 读锁

    共享锁)针对同一份数据多个操作同时进行而不会互相影响
    mysql高级(四)——锁

    当前session 其他session
    可以查询当前锁定的表 可以查询被锁定的表
    不可以查询其他未被锁定的表 可以查询其他未被锁定的表
    不可以更新当前锁定的表,报错 可以更新被锁定的表,但是阻塞
    释放读锁 阻塞结束,更新成功
  • 写锁

    排它锁)当前写操作没有完成前会阻断其他写锁和读锁
    mysql高级(四)——锁

    当前session 其他session
    不可以查询其他未被锁定的表,报错 可以查询其他未被锁定的表
    可以更新当前锁定的表 可以更新被锁定的表,但是阻塞
    可以查询当前锁定的表 可以查询被锁定的表,但是阻塞
    释放读锁 阻塞结束,更新,查询成功

总结:读锁会阻塞写,但是不会阻塞读;写锁则会把读和写都阻塞
查看那些表被加锁了:show open tables;
mysql高级(四)——锁

结论:myisam的读写锁调度是锁优先,不适合做写为主表的引擎;因为写锁后,其它线程不能进行任何操作,大量的更新回使查询阻塞。


行锁(偏向InnoDB引擎)

  • 事务

    innodb和myisam的区别:一是支持事务,二是采用了行级锁(冲突低,并发度高)

    mysql高级(四)——锁

    脏读:是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
    不可重复读:是指在一个事务处理过程里读取了另一个提交的事务中更新的数据。
    虚读(幻读):是指在一个事务处理过程里读取了另一个提交的事务中新增的数据。
      幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

    MySQL数据库为我们提供的四种隔离级别:
      ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
      ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
      ③ Read committed (读已提交):可避免脏读的发生。
      ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

    以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。
      在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。

    在MySQL数据库中查看当前事务的隔离级别:
    select @@tx_isolation;
    在MySQL数据库中设置事务的隔离 级别:
    set [glogal | session] transaction isolation level 隔离级别名称;
    set tx_isolation=’隔离级别名称;’

行锁

mysql高级(四)——锁

一个事务开启,使用索引为条件更新数据会把这一行数据锁定,其他事物要更新这条数据需等待锁释放

表锁
mysql高级(四)——锁
生产中切记字段类型,一面索引失效导致全表锁

死锁
我们再来举一个常见的高并发下的死锁的问题:

有两个并发更新事务A B,A执行update from account set money =600 where id in (1,2,3);B执行update from account set money =600 where id in (2,3,4)
mysql高级(四)——锁
可以看出这种sql使用了索引,那么就不会导致表锁只会锁定in条件的几行
那么问题就来了,事务A执行锁定完1和3行,准备锁定2行的时候;不巧这时候B锁定了2和4行。A事务只能等待B释放2行的锁,阻塞;而B这时候如果执行完事务那么就释放了锁,大家皆大欢喜,但是B也要去锁定3行,这时候3行的锁被A事务占用,就导致B也阻塞。最终两个事物都在相互阻塞,产生死锁。

间隙锁

mysql高级(四)——锁

对于mysql这种宁可错杀不放过的对间隙锁的处理有时候会对系统造成不可预期的危害

如何锁定一行

mysql高级(四)——锁

这是手动锁定一行数据的方法
查看mysql行锁分析:
mysql高级(四)——锁