MySQL数据库锁,mysql锁机制
所谓锁,是为了保证数据的一致性,对共享资源的并发访问变得有序的一种规则。
不同的MySQL存储引擎有不同的锁机制或锁实现;一般来说,使用三种锁级别,即行级锁、页级锁和表级锁。锁定资源的粒度逐渐减小。随着被锁资源粒度的降低,锁同样的数据需要越来越多的内存,算法也越来越负责。但与此同时,应用程序遇到锁等待的可能性越来越低,而且
表级锁,各存储引擎粒度最大的锁级,实现简单,获取和释放锁的速度快,避免了死锁问题,但同时带来锁资源竞争的问题,导致并发低;表锁分为读锁和写锁。MySQL通过四个队列来维护这两种锁,其中两个队列存储当前被锁的读写信息,两个队列存储等待读写的信息。这四个队列分别是:read-lock read _ wait-lock-write-lock/write _ wait-lock;读锁,当前请求获取锁的资源没有被写锁锁定,写锁等待队列中没有更高优先级的写锁等待,所以立即进入读锁,如果没有,进入read _ wait-lock;写,当前请求写的资源没有被写锁定,且不在写锁定的等待队列中,则检查其是否在读的等待队列中,如果是,则进入写的等待队列,如果不是,则进入当前写队列;表级锁通常由一些非事务存储引擎使用,如MyISAM、Memory、CSV等。
页面级锁毕竟是MySQL中的特殊锁级。其粒度介于行级锁和表级锁之间,获取和释放锁资源的负担也介于行级锁和表级锁之间,其并发性也介于行级锁和表级锁之间。与行级锁一样,页级锁可能会死锁。主要的BerkeleyDB存储引擎是锁定模式;
行级锁是RMDB实现的锁粒度最小的锁,资源竞争的概率最小,可以提供尽可能多的并发处理来提供应用性能。但同时,由于粒度较小,获取和释放锁需要最大的消耗。此外,行级锁最容易出现死锁;行锁不是由MySQL实现的,而是由存储引擎实现的,比如InnoDB和MySQL的分布式存储引擎NDBCluster。InnoDB的行级锁也分为两种,共享锁和独占锁。同样,InnoDB也引入了意向锁(表级锁)的概念,所以有意向共享锁和意向排他锁。所以InnoDB其实有四种锁,分别是共享锁(S)、排他锁(X)、有意共享锁(IS)和有意排他锁(IX)。
如果某些资源已经有一个共享锁,则可以将其他共享锁添加到这些资源中,但是不能添加独占锁。如果某些资源已经有独占锁,则不能向这些资源添加其他独占锁和共享锁。您只能等待当前锁被释放并获得锁定的资源,然后才能锁定它们,但您可以为它们添加有意锁定。也就是说,如果等待的事务想要添加排他锁,可以向锁定行的表中添加一个有意的排他锁;如果等待的事务想要添加一个共享锁,您可以向锁定行的表中添加一个有意的共享锁。InnoDB的锁实现与Oracle的锁实现有很大不同。一般来说,Oracle根据一行记录所在的物理块上的事务槽中的表级锁信息来锁定数据,而InnoDB通过在数据记录的第一个索引前后的空域中标记锁信息来锁定数据。所以InnoDB的这种锁实现被称为“下一键锁”(gap locking)。gap locking的一个很大的弱点就是,在锁定了一定范围的键值后,即使是一些不存在的键值也会被无辜锁定,导致这类键值的记录没有被插入。当然,这只会在InnoDB的默认事务隔离级别是repeatable-read时发生,但如果InnoDB的事务隔离级别降低到read commited,这就不会发生。InnoDB给出的解释是间隙锁可以防止幻影读取的发生,但实际上间隙锁只能防止部分幻影读取的情况,而不是全部。索引锁定的方式存在更大的隐患。当查询不能使用索引时,行级锁会上升到表级锁,表级锁会锁定整个数据表,导致并发性能降低。
死锁,行级锁可能会导致死锁,InnoDB也不例外。InnoDB有一套检测死锁的机制,但前提是死锁场景中涉及的所有存储引擎都是InnoDB。如果InnoDB检测到死锁,它将影响数据行数最少的事务的回滚。
那么有什么办法可以避免InnoDB的清仓锁带来的麻烦呢?有三种方式:1。减少并发,避免资源竞争,但这会在一定程度上降低应用的性能;2.将InnoDB的默认事务隔离级别从repeatable-read修改为read commited。当然,修改事务隔离级别带来的另一个隐患是不可重复读取的可能性。3.查询数据时,一定要使用索引,避免扫描整个表。插入数据时,使用增加的索引字段(即每次插入的索引字段的值必须保证增加);
参考文件:
http://www.doc88.com/p-0028745479299.html
http://www . cn blogs . com/ggjucheng/archive/2012/11/14/2770445 . html