MySQL锁机制的示例分析
MySQL是一款非常流行的关系型数据库,但是随着网站用户越来越多,MySQL的并发读写能力逐渐成为了网络应用开发者关注的问题,为了解决这个问题MySQL引入了锁机制。
MySQL的锁机制主要分为以下两类:
1. 表级锁
MySQL中的表级锁是对整张数据表进行加锁,它可以把整张表加锁,阻止其他线程访问该表,也可以对该表指定加锁的部分,这样可以防止其他线程仅仅在那个部分进行操作。
那么表级锁具体是如何实现的呢?我们来看一下下面的例子。
创建一张测试表
mysql> CREATE TABLE lock_test (id INT PRIMARY KEY, name VARCHAR(10)); Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO lock_test VALUES (1, '张三'), (2, '李四'), (3, '王五'); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0
打开两个MySQL连接,一个执行UPDATE操作,一个执行SELECT操作。
Session 1: mysql> UPDATE lock_test SET name='赵六' WHERE id=3; Session 2: mysql> SELECT * from lock_test WHERE id=3;
如果Session1的UPDATE操作执行完之前,Session2的SELECT操作就已经执行完了,那么输出就是如下所示:
mysql> SELECT * from lock_test WHERE id=3; +----+--------+ | id | name | +----+--------+ | 3 | 王五 | +----+--------+ 1 row in set (0.00 sec)
那如果Session1的UPDATE操作早于Session2的SELECT操作执行完,那么Session2执行的结果就是:
mysql> SELECT * from lock_test WHERE id=3; Empty set (0.00 sec)
从以上例子中可以看出,表级锁是保证整张表的并发读写一致性的一种方法。但是,它的并发量非常有限,因为它只能单向控制的单一事务的并发读写。
2. 行级锁
相对于表级锁来说,MySQL的行级锁就是对数据表中的单行记录进行加锁,这样就可以让其他线程自由地访问该表中其他的记录。但实际上,行级锁并不是MySQL内部的一个技术,而是在InnoDB存储引擎中实现的。
MySQL的行级锁机制主要由共享锁和排他锁两种模式实现,共享锁可以允许多个线程读取同一行记录,但阻止其他线程进行修改或删除该行记录;排他锁则具有最高的优先级,防止同一行记录被其他线程读取或修改。
那么行级锁的实现原理又是什么呢?我们来看一下下面的例子。
打开两个MySQL连接,连接1采用排他锁更新一行数据,连接2采用共享锁查询一行数据:
Session 1: mysql> BEGIN; mysql> SELECT * from lock_test WHERE id=2 LOCK IN SHARE MODE; mysql> UPDATE lock_test SET name='张三三' WHERE id=2; mysql> COMMIT; Session 2: mysql> BEGIN; mysql> UPDATE lock_test SET name='李四四' WHERE id=2 LOCK IN SHARE MODE;
Session1的UPDATE操作执行之前,Session2已经加锁了,但Session1并没有回滚,因为Session2访问的是共享锁,而Session1更新该行数据的时候已经使用了排他锁,所以Session2的共享锁被允许。
从以上例子中可以看出,行级锁中的共享锁与排它锁并非不可折衷的,通过使用这两种锁,我们可以让多个线程同时读取相同的记录,但只允许一个线程写入。并且很重要的一点,行级锁会在事务结束后自动释放,保证数据的一致性。
总结:MySQL的锁机制因为是对整张表或者单行记录进行加锁,所以很容易成为瓶颈。为了尽量减少锁的使用,我们应该尽量避免使用大事务,同时优化数据库表结构,使其更符合设计的规则,以降低锁的并发度。
