MySQL系列-MyISAM表锁详解

1.S锁和X锁

S锁(共享锁)

又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改,除非先获取A的X锁。

X锁(排他锁)

又称写锁,若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。

2.MyISAM的锁机制和innoDB的锁机制

MyISAM只支持表锁,锁的是整张表,读取数据的时候会加S锁,增删改的时候会加X锁

innoDB既支持表锁也支持行锁,可以锁行级别的数据,增删改的时候会对数据对象(可能是一行或者多行或者一张表)加X锁,读取的时候一般不加锁,因为innoDB实现MVCC(Multi-Version Concurrency Control 多版本并发控制)。后面我会出一篇博客详细讲解innoDB的锁机制以及它的MVCC。

3.实际测试MyISAM的表锁(MySQL5.5版本)

首先准备一张MyISAM的表。



为了模拟高并发场景我们可以手动加锁(如果不手动加锁,他也会隐式的自动加锁和自动释放锁)

lock table name read;  给name表加S锁

lock table name write;  给name表加X锁

也可以一次性给多张表加锁

lock table name1 read,name2 write;

释放所有获得的锁

unlock tables;


测试一:测试mb表的S锁和X锁


可以看到,两个会话都成功数据对象加了S锁。

但是会话1不能更新数据。除非让第二个会话放弃S锁,然后第一个会话再加X锁,获取锁成功后才能更新数据。如果锁被其他会话占用 而没有获取成功的话会话1会一直等待获取,直到达到设置的超时时间。



测试二:加了X锁真的就立马不能读取数据吗?

如果会话1对数据对象加了X锁,但是这个时候还没有修改数据,而会话2却查询了数据,还是有可能可以获取数据的,但是一但会话1修改了数据那么会话2就不能再获取数据了,必须等会话1释放X锁。这个其实很好理解,MySQL底层是有个查询缓存的,当我们会话1没有修改数据的时候如果查询缓存当中有数据,那么这个数据是有效的,一但会话1修改了数据这个时候查询缓存就无效了,这样设计可以提升一点效率,而又不违背X锁和S锁的设计的原则。


可以看到,我们先把mb表给锁了,然后查询数据,这个时候会话1没有修改数据,但是会话2也没有查询缓存所以仍然查询不了数据。

接下来我们再测试。先让会话2先查询一次数据,然后会话1在加X锁,然后会话2再发送同样的sql语句。


可以看到还是成功的获取了数据。那如果这个时候会话1修改了mb表的数据呢?


可以看到,会话2的查询语句一直在等待,直到会话1释放X锁。


当会话1释放了X锁会话2也就顺利执行了查询语句。

4.MyISAM发生死锁

当会话1获取了A表的X锁,会话2获取了B表的X锁,而会话1又在尝试获取B表的X锁,会话2在尝试获取A表的X锁,这个时候就发生死锁了。

但是一般这种情况不会存在的,因为MyISAM不支持事务,相当于每一条SQL就是一个事务,当某个会话执行完一条语句之后会立马把锁给释放,并不会把锁保留,也就是说不存在同时需要占用两个锁的情况。当然我们可以手动加锁模拟这个场景。

在MyISAM下,当发生死锁时,MySQL会自动把会话持有的锁给释放。


会话1的ma的x锁被释放给了会话2,会话2的mb的x锁释放给了会话1。

当然在实际做项目的时候也不会去这样做,一般不会手动加锁而是让会话执行sql语句的时候自动加锁和自动释放锁。


前面所有的测试在innoDB上有同样的效果,因为innoDB一样支持表锁。


参考文章

http://hudeyong926.iteye.com/blog/1489929

猜你喜欢

转载自blog.csdn.net/ufo___/article/details/80794902