从性能上分为乐观锁(用版本对比来实现)和悲观锁
从对数据库操作的类型分,分为读锁和写锁(都属于悲观锁)。
读锁(共享锁,S锁(Shared)):针对同一份数据,多个读操作可以同时进行而不会互相影响
写锁(排它锁,X锁(eXclusive)):当前写操作没有完成前,它会阻断其他写锁和读锁
从对数据操作的粒度分,分为表锁和行锁
表锁与行锁表锁每次操作锁住整张表。
开销小(不需要定位到某个元素,只需要定位到表),加锁快;
不会出现死锁;
锁定粒度大,发生锁冲突的概率最高,并发度最低;
一般用在整表数据迁移的场景。
表锁操作方式手动增加表锁:locktable表名称read(write),表名称2read(write);
查看表上加过的锁showopentables;
删除表锁unlocktables;
行锁每次操作锁住一行数据。
开销大,加锁慢;
会出现死锁;
锁定粒度最小,发生锁冲突的概率最低,并发度高。
InnoDB与MYISAM的最大不同点:InnoDB支持行级锁、支持事务
MyISAM在执行查询语句SELECT前,会自动给涉及的所有表加读锁,在执行update、insert、delete操作会自动给涉及的表加写锁。
InnoDB在执行查询语句SELECT时(非串行隔离级别),不会加锁。但是update、insert、delete操作会加行锁。
行锁操作方式sql后增加forupdate来实现行锁。
forupdate在不走索引的时候会锁表!但是当要修改或者查询的数据不存在的时候,不会锁表,也不会锁定行!
读锁与写锁读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞。
乐观锁与悲观锁乐观锁乐观锁时会假设在极大多数情况下不会形成冲突,只有在数据提交的时候,才会对数据是否产生冲突进行检验。发生冲突后,不修改数据
实现方式在数据库表中增加一列,记为version,当我们将数据读出时,将版本号一并读出,当数据进行更新时,会对这个版本号进行加1,当我们提交数据时,会判断数据库表中当前的version列值和当时读出的version是否相同,若相同说明没有进行更新的操作,不然,则取消这次的操作。
悲观锁MySql的悲观锁就是打开事务,当启动事务时,如果事务中的sql语句涉及到索引并用索引进行了条件判断,那么会使用行级锁锁定所要修改的行,否则使用表锁锁住整张表。
实现方式sql后增加forupdate来实现悲观锁。
forupdate在不走索引的时候会锁表!
当要修改或者查询的数据不存在的时候,不会锁表,也不会锁定行!
当InnoDB表有多个索引的时候,不同事务使用不同的索引去锁定同一条记录是怎么处理的虽然用的不同辅助索引,但是相应的聚簇索引也会加锁,也就是主键会加锁,这样就防止并发修改了
间隙锁(GapLock)与临键锁(Next-keyLocks)间隙锁间隙锁,锁的就是两个值之间的空隙。
间隙锁是在可重复读隔离级别下才会生效。
在普通索引列上,不管是何种查询,只要加锁,都会产生间隙锁,这跟唯一索引不一样;
在普通索引和唯一索引中,数据间隙的分析,数据行是优先根据普通索引排序,再根据唯一索引排序。
产生的条件使用普通索引锁定;
使用多列唯一索引;
使用唯一索引锁定多行记录。
间隙锁开启状态处理:innodb_locks_unsafe_for_binlog默认值为OFF,即启用间隙锁。
此参数是只读模式,如果想要禁用间隙锁,需要修改my.cnf(windows是my.ini)重新启动才行。
查看是否禁用:showvariableslike‘innodb_locks_unsafe_for_binlog’;
间隙锁的范围说明唯一索引:id的间隙SELECT*FROMtableWHEREid3ANDid7FORUPDATE;产生的间隙为(1,10】
普通索引:name的间隙SELECT*FROMtableWHEREname=‘5’FORUPDATE;产生的间隙为(1,10】
临键锁(Next-keyLocks)行锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间
这是Innodb在可重复读提交下为了解决幻读问题时引入的锁机制,
MySQL默认隔离级别是RR(可重复读),在这种级别下,如果你使用selectinsharemode或者selectforupdate语句,那么InnoDB会使用临键锁(记录锁+间隙锁),因而可以防止幻读;
即使你的隔离级别是RR(可重复读),如果你这是使用普通的select语句,那么此时InnoDB引擎将是使用快照读,而不会使用任何锁,因而还是无法防止幻读。