锁之于数据库是非常重要的,它为数据的正确性作出了重要的贡献。锁按照粒度可以分为三种:表级锁、块级锁和行级锁。
表级锁
当你对数据进行加锁时,只能锁定一整张表,存储引擎为MyISAM提供的是表级锁,这是粒度最粗的一级锁。表级锁有两种模式:读锁和写锁。当加上读锁时,如果没有释放该锁,表数据将不能更新(因为表更新时要申请写锁),当加上读锁时,另一线程也可对表加上读锁,因为读读是可以共享的,又称之为共享锁。当加上写锁时,表即不能被读取,也不能为其他线程加上写锁,因为边写读边和写写都会导致错误,又称之为排他锁。
表级锁之共享锁
当使用select语句进行表查询时,MyISAM会自动对表加上表级共享锁,此时,对表的更新都需要等待。
表级锁之排他锁
当进行数据更新时,为了保证正确,要先加上排他锁,使用lock table 表名称 write,此时无论是对表的查询或是更新都需要等待,使用完毕之后unlock tables来释放锁。
块级锁
可以支持对整张表中的一段进行加锁,粒度适中,旧的BDB存储引擎使用的是这种锁。
行级锁
只对表中的某行数据进行加锁,粒度最细,InnoDB使用的就是这种锁。行级锁的实现在Mysql中是通过对索引进行加锁实现的,如果你使用的条件是加上索引的列,那么InnoDB是采用行级锁,如果该条件是没有加上索引的,则InnoDB使用的是表级锁。
行级锁之共享锁
在指定的sql语句后面加上share mode可以对InnoDB加上行级共享锁。
行级锁之排他锁
在指定的sql后面加上for update可以加上行级排他锁。
3.为engin=innodb类型加上行级锁
这里需要知道的是,innodb即可以支持行级锁,也可以支持表级锁,当你在SQL语句中指定主键时,innodb才会去加上行级锁,否则加上表级锁。
在where子句中是否将主键做搜索条件,如果是主键做搜索条件,将使用行级锁,否则使用表级锁。
在Mysql中进行加锁
1.为表加上读锁/写锁
lock tables tablename1 [read|write], tablename2 [read|write],...;
2.为表解除读/写锁
unlock tables;
3.为engin=innodb类型加上行级锁
这里需要知道的是,innodb即可以支持行级锁,也可以支持表级锁,当你在SQL语句中指定主键时,innodb才会去加上行级锁,否则加上表级锁。
select ...for update
在where子句中是否将主键做搜索条件,如果是主键做搜索条件,将使用行级锁,否则使用表级锁。
三种锁之间的性能比对
1.表级锁:加锁的开销最小,速度最快,但代价是支持的并发降低,冲突 概率最高(因为资源的范围最广),不会产生死锁。
2.块级锁:加锁的开销介于行级锁与表级锁之间,速度也介于行级锁与表级锁之间,支持的并发度一般,冲突概率介于表级锁和行级锁之间,会产生死锁。
3.行级锁:加锁的开销最大,速度最慢,但是支持的并发最高,会产生死锁。
锁的选择
目前Mysql主流的存储引擎是MyISAM和InnoDB,所以也就讨论表级锁和行级锁。一般来说,如果读操作远远高于写操作(查询居多,有少量更新),那么使用表级锁为宜,更新多会导致更新队列过长,更新延时高;如果即有大量写操作,又有较多的读操作,那么就使用行级锁。