锁模块
InnoDB和MyISAM关于锁方面的区别是什么
InnoDB默认用的是行级锁,也支持表级锁,不使用索引的时候用的是表级锁。
MyISAM默认用的是表级锁,不支持行级锁。
共享锁(S) | 排他锁(X) | 意向共享锁(IS) | 意向排他锁(IX) | |
---|---|---|---|---|
共享锁(S) | 兼容 | 冲突 | 兼容 | 冲突 |
排他锁(X)) | 冲突 | 冲突 | 冲突 | 冲突 |
意向共享锁(IS) | 兼容 | 冲突 | 兼容 | 兼容 |
意向排他锁(IX) | 冲突 | 冲突 | 兼容 | 兼容 |
InnoDB适用的场景
-
数据增删改查都非常频繁
-
可靠性要求比较高,要求支持事务
MyISAM适用的场景
-
频繁执行全表count语句。MyISAM用一个变量保存了整个表的行数
-
对数据进行增删改的频率不高,查询非常频繁。增删改会有锁表操作,插入从表的尾部插入,会有很多碎片。
-
没有事务的场景
数据库锁的分类
- 按锁的粒度划分,可分为表级锁、行级锁、页级锁
- 按锁级别划分,可分为共享锁、排他锁
- 按加锁方式划分,可分为自动锁、显式锁 (for update 、lock in share mode)
- 按操作划分,可分为DML锁(数据操作时加的锁)、DDL锁(表结构变更加的锁)
- 按使用方式划分,可分为乐观锁、悲观锁
数据库事务的四大特征(ACID)
-
原子性(Atomic):事务包含的所有操作要么全部执行,要么全不执行,失败回滚
-
一致性(Consistency):数据能够满足完整性约束,两个有关联的数据,一个改变,另一个也随之改变
-
隔离性(Isolation):当多个用户并发访问数据 库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务操作所干扰,多个并发事务之间要相互隔离
-
持久性(Durability):指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作
事务的隔离级别以及各级别下的并发访问问题
一、事务并发访问引起的问题
- 更新丢失(Lost Update):两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。这是因为系统没有执行任何的锁操作,因此并发事务并没有被隔离开来。
- 脏读(Dirty Read):又称无效数据读出。一个事务读取另外一个事务还没有提交的数据叫脏读。例如:事务T1修改了一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,之后事务T1因为某种原因回滚了,那么事务T2读取的数据就是脏的。
- 不可重复读(Non-Repeatable Read):是指在一个事务中两次读同一行数据,可是这两次读到的数据不一样。例如:事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。
- 幻读:事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据。
例如:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样。
不可重复读侧重于对同一数据的修改,幻读侧重于对数据的新增或删除。
二、事务的隔离级别
以上的4种问题(更新丢失、脏读、不可重复读、幻读)都和事务的隔离级别有关。通过设置事务的隔离级别,可以避免上述问题的发生。
- 读未提交(Read Uncommitted):读事务不阻塞其他读事务和写事务,未提交的写事务阻塞其他写事务但不阻塞读事务。此隔离级别可以防止更新丢失,但不能防止脏读、不可重复读、幻读。此隔离级别可以通过“排他写锁”实现。
- 读已提交(Read Committed):读事务允许其他读事务和写事务,未提交的写事务禁止其他读事务和写事务。此隔离级别可以防止更新丢失、脏读,但不能防止不可重复读、幻读。此隔离级别可以通过“瞬间共享读锁”和“排他写锁”实现。
- 可重复读取(Repeatable Read):以操作同一行数据为前提,读事务禁止其他写事务但不阻塞读事务,未提交的写事务禁止其他读事务和写事务。此隔离级别可以防止更新丢失、脏读、不可重复读,但不能防止幻读。此隔离级别可以通过“共享读锁”和“排他写锁”实现。
- 序列化(Serializable):提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。此隔离级别可以防止更新丢失、脏读、不可重复读、幻读。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免更新丢失、脏读,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
当前读和快照读
当前读:加了锁的增删改查语句,像select … lock in share mode,select … for update;update,delete,insert;读取当前记录的最新版本,并且保证其他并发事务不能修改当前记录。
快照读:不加锁的非阻塞读,select;在Serializable级别的快照读也变成为当前读;
可重复读下避免幻读
next-key锁(行锁+gap锁),gap锁(间隙锁)目的是防止同一事务的两次当前读出现幻读的情况。
对主键索引或者唯一索引会用gap锁吗?
-
如果where条件全部命中,不会用gap锁,只会加记录锁;
-
如果where条件部分命中或全都不命中,会加gap锁;
gap锁出现在非唯一索引或不走索引的当前读中