概述
数据库的锁机制,是数据库为了保证数据的一致性,使各种共享资源在被访问时变得有序而设计的一种规则。 InnoDB支持行锁,有时也会升级为表锁 MyISAM只支持表锁 多个并发事务修改数据,表锁会锁住整个表,不让多个事务同时修改,而行锁是锁住其中一行数据,其他行的数据依然可以由其他并发事务修改。 表锁的特点:开销小,加锁块,不会出现死锁。锁粒度大,发生锁冲突的概率小,并发度相对低。 行锁的特点:开销大,加锁慢,会出现死锁,锁粒度小,发生锁冲突的概率高,并发度高。
InnoDB行锁的种类
记录锁
普通的行锁 锁住某一条记录(一行数据)。 有索引,行锁生效, 没有索引,为表锁
间隙锁
在可重复读这个级别下,为了避免幻读,引入了间隙锁,它锁定的是记录范围,不包含记录本身,也就是不允许在范围内插入数据。 间隙:根据检索条件向下寻找最靠近检索条件的记录值A作为左区间,向上寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A, B)
临键锁
记录锁和间隙锁的组合 它的封锁范围,既包含索引记录,又包含索引区间。 临键锁的主要目的,也是为了避免幻读,如果把事务的隔离级别降级到RC(提交读),临键锁会失效。
表锁
第一种情况:事务需要更新大部分或者全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。 第二种情况:事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚,这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁,减少数据库因事务回滚带来的开销。
InnoDB的锁类型
读锁(共享锁)
简称S锁,一个事务获取了一个数据行的读锁,其他事务能获得该行对应的读锁但不能获得写锁,即一个事务在读取一个数据行时,其他事务也可以读,但不能对该行增删改的操作。 简言之:可以多个事务读,但只能一个事务写。
写锁(排他锁)(独占锁)
简称X锁。一个事务获取了一个数据行的写锁,其他事务就不能再获取该行。
意向锁
在InnoDB引擎中,意向锁是表级锁,意向锁有两种: 意向共享锁:指在给一个数据行加共享锁前必须获取该表的意向共享锁。 意向排他锁:指在给一个数据行加排它锁前必须获取该表的意向排它锁。
MDL锁
meta data lock,简称MDL锁。 用于保证表中元数据的信息。在会话A中,表开启了查询事务后,会自动获得一个MDL锁,会话B就不可以执行任何DDL语句,不能执行为表中添加字段的操作,会用MDL锁来保证数据之间的一致性。
注:元数据就是描述数据的数据,也就是表结构。 意思是在开启了事务之后获得了意向锁,其他事务就不能更改你的表结构了。
意向锁和MDL锁都是为了防止在事务进行中,执行DDL语句导致数据不一致。
另一个角度分类
乐观锁
手动实现。 比如: 乐观锁大多是基于数据版本记录机制实现。一般是给数据库表增加一个“version”字段。读取数据时,将此版本号一同读出,之后更新时,对此版本号加1。此时将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。先查再修改
悲观锁
悲观锁依靠数据库提供的锁机制实现。MySQL中的共享锁和排它锁都是悲观锁(上面学的全是悲观锁) 数据库的增删改操作默认都会加排它锁,而查询不会加任何锁。
锁等待和死锁
锁等待是指一个事务过程中产生的锁,其他事务需要等待上一个事务释放它的锁,才能占用该资源。 如果事务一直不释放,就需要持续等待下去,知道超过了锁等待时间,会报一个等待超时的错误。
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象。
InnoDB引擎可以自动检测死锁并回滚该事务。但是好不容易执行了一个业务,可能都快执行完了最后却回滚了太可惜,所以死锁尽量不要出现。
如何避免死锁
1.如果不同的程序会并发处理同一个表,或者涉及多行记录,尽量约定好顺序来访问表,可以减少死锁的发生。 2.业务中尽量采用小事务,避免使用大事务,要及时提交和回滚事务,减少死锁产生的概率。 3.同一个事务中尽量做到一次锁定所需要的所有资源,减少死锁发生的概率 4.对于非常容易发生死锁的业务,可以尝试使用升级锁的力度,改用表锁减少死锁的发生。
总结
|