为什么需要锁?
锁是为了保证数据库中数据的一致性,使各种【共享资源】在被访问时变得【有序】而设计的一种规则。
mysql中不同的存储引擎支持不同的锁机制,inoDB支持行锁,有时也会升级为表锁,MyIsam只支持表锁。
【表锁】开销小,加锁快,锁的粒度大,不会出现死锁,发生锁冲突的概率小,并发性能较低
【行锁】开销大,加锁慢,锁的粒度小,会出现死锁,发生锁冲突的概率大,并发性能较高
读锁(共享锁/S锁)
读锁(共享锁)简称S锁,一个事务获取了一个数据行的读锁,其它事务也能获取该行对应的读锁,但不能获得写锁,即一个事务在读一个数据行时,其它事务也可以读,但不能对该数据行进行增删改的操作。
注:读锁是共享锁,多个事务可以同时持有,当有一个或多个事务持有共享锁时,被锁的数据就不能修改。
写锁(排他锁/独占锁/X锁)
写锁(排他锁/独占锁)简称X锁,一个事务获取了一个数据行的写锁,即可以读该行的数据也可以修改该行的数据,但其它事务就不能获取该行的其它任何锁,包括S锁,直到当前事务将锁释放。
注:写锁是独占锁,只有一个事务可以持有,当这个事务持有写锁时,被锁的数据就不能被其它事务读取和修改。
记录锁(行锁)
记录锁就是我们常说的行锁,只有innodb支持,以下有几个案例验证行锁的存在:


备注:这不仅验证了行锁的存在,而且证明行锁事加在索引上的,所以尤其要注意的是在以后牵扯到更新/删除操作的时候,where条件的列一定要加索引,不然会导致锁表。
表锁
对于innodb而言,在绝大部份情况下都应该使用【行级锁】,因为事务和行锁往往是我们选择innodb引擎的理由,但在特殊事务中,也可以使用表级锁:
1、事务需要更新【大部分或全部数据】,表又表较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其它事务长时间锁等待和锁冲突。
2、事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚,这种情况也可以考虑一次性锁定事务所涉及的表。
间隙锁
间隙锁帮我们解决了mysql在rr(可重复读)级别下的部分幻读问题。间隙锁锁定的是记录范围,不包含记录本身,也就是不允许在某个范围内插入数据。
间隙锁生成的条件:
1、A事务使用where进行范围检索时未提交事务,此时B事务向A满足检索条件的范围内插入数据。
2、where条件必须有索引。
乐观锁
乐观锁大多是基于数据【版本记录机制】实现,一般是给数据库表增加一个“version”字段。
读取最新版本号的数据,更新时对此版本号加1。此时将提交数据的版本信息与数据库中对应记录的当前版本信息对比,如果提交数据的版本号大于数据库表当前版本号则予以更新,否则认为是过期数据。
悲观锁
总有刁民想害朕!
悲观锁依靠数据库提供的锁机制实现。Mysql中的共享锁和排它锁都是悲观锁,数据库的增删改操作默认都会加排它锁。
innoDB的mvcc模式
1.MVCC全称Muti-Version Concurrency Control,即多版本并发控制。
多版本并发控制:指的是一种提高并发的技术,最早的数据库系统只有读读可以并发,读写、写写、写读之间都要阻塞,引入多版本之后,只有写写之间相互阻塞,其它操作都可以并行,这样就大大提高了innodb的并发度,在内部实现中innodb是通过undo log实现的,通过undo log可以找回数据的历史版本(快照读)。找回的历史版本可以提供给用户读。
2.当前读与快照读
备注:现在innodb的正常读取就是普通读(快照读)。
当前读
像共享锁/排它锁这些操作就是一种当前读,因为它读取的是数据的最新版本,读取的时候还要保证其它事务不能修改当前记录,会对记录进行加锁。
快照读
mvcc模式就是一种快照读