一、按机制:共享锁(读锁)、排他锁(独占锁)(写锁)
1、共享锁:
概念:也称读锁,S锁。当事务对数据(这里的数据可以是全局库、表、行)加上共享锁后,其他事务只能对该数据进行读操作,不能进行写操作。 用途:因为在读的时候不允许其他事务修改,所以能够解决不可重复读的问题。 用法:
select … lock in share mode
2、排他锁,也称独占锁:
概念:又称写锁,X锁。当事务对数据(同上),加上排它锁后,其他事务不能对该数据进行读写操作。 用途:因为在读写数据的的时候不允许其他事务读写,所以能够解决脏读的问题。 用法:
select …for update
二、按粒度:全局锁、表锁、行锁
1、全局锁:
概念:针对整个库的锁,又分全局读锁和全局写锁,读写锁和上面所介绍的读写锁的功能一致。 用途:当需要进行一些全库导出、备份的操作时,全局锁可以有效保证数据的一致性。 用法:
Flush tables with read lock // (FTWRL),加锁
unlock tables//解锁
2、表锁:
概念:针对表的锁,又分表读锁和表写锁。加锁快,但锁冲突概率高。 用途:适合一些读多写少的应用场景,适合全表删除或者更新的场景使用。 用法:
lock tables '表名' read/write;
unlock tables//解锁
3、行锁:
概念:针对行的锁,又分读锁和写锁,但锁冲突概率低,但更耗资源,容易死锁。 特别地: ①.只在事务中有效,在非事务的sql在执行完会执行释放。 ②.行锁实际上锁的是行记录的索引 ,如果加锁时没有用到索引,也就会进行全表扫描,从而使得行锁退化为表锁。 ③.如果加锁时用到了非主键索引,那么会先锁住非主键索引,再回表找到主键索引后再锁主键索引。 ④.如果加锁时进行了UPDATE、DELETE操作时,会进化为临键锁(next-key locking) 用途:适合高并发读写场景、短期的锁定及复杂的事务处理场景 用法:在事务中对单行进行以下操作时
select … lock in share mode
select …for update
insert//对当前新增行
uptdate//对当前修改行
delete//对当前删除行
三、按业务:乐观锁、悲观锁
1、乐观锁:
概念:乐观锁在mysql中并没有内置实现,是通过编程技术手段实现的。他假设大多数情况下都不会发生锁冲突,如果发生冲突,可进行回滚或者再次重试。 用途:适合一些读多写少,锁冲突概率较小的场景,如果写多锁冲突规律大,则会发生大量回滚或者不断重试,影响性能。 用法: ①.设置一个字段version ②.每次开启事务更新前先查一便拿到当前version号 ③.更新时连同version一起更新并且条件带上version=#{verison},如果失败,则回滚. ④.案例:在业务层实现
Ⅰ. 查询订单信息
select id, status, version from order where id= #{ id} ;
Ⅱ. 查询其他信息并处理
. . .
Ⅲ. 修改订单状态
update set status= 支付成功, version= version+ 1 where id= #{ id} and version= #{ version} ;
2、悲观锁:
概念:悲观锁假设每次操作都会发生冲突,因此每次操作前都会加锁。 用途:适合一些写多读少,锁冲突概率较大,或数据强一致性的场景。 用法:在mysql中主要就是使用共享锁和排他锁实现,即
select … lock in share mode
select …for update
四、按算法:记录锁、间隙锁、临键锁
1、记录锁:即为行锁
2、间隙锁:
概念:存在于纪录之间的间隙上的锁,作用范围为左开右开,不锁记录本身。仅在RR事务隔离级别下有效。 例如有表,以下存在间隙锁(-∞,1),(1,3),(3,5); 当一事务select … where id=3 for update时,另一事务。insert id=2时,无法插入
用途:间隙锁会封锁某条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,为了解决幻读 用法:MySQL自身存在
2、临键锁:
概念:是间隙锁+纪录锁的结合,即既锁记录间的间隙,作用范围为左开右闭,也锁记录本身。仅存在RR事务隔离 级别,而且临键锁只与非唯一索引列有关,在唯一索引列(包括主键列)上不存在临键锁。 例如以下的表则以上存在间隙锁(-∞,1],(1,3],(3,5];
五、按意向:意向共享锁、意向排他锁
概念:两个锁均为表锁,在对表里某些记录加上共享锁之前,会先在表级别加上一个意向共享锁。 同理,在加上排他锁前。。。 用途:那么有了意向锁,如果想对表加锁,那么会直接查该表是否有意向独占锁,如果有就意味着表里已经有记录被加了锁,这样就不用去遍历表里的记录。也就是是为了快速判断表里是否有记录被加锁 。 意向锁只与表锁互斥,与其他行锁不互斥。