前言
读这篇文章之前可以先了解一下MySQL中InnoDB数据结构
一、InnoDB引擎对隔离级别的支持
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 可能 | 可能 | 可能 |
不可重复读(read-committed) | 不可能 | 可能 | 可能 |
可重复读(repeatable-read) | 不可能 | 不可能 | InnoDB不可能 |
串行化(serializable) | 不可能 | 不可能 | 不可能 |
隔离级别到底如何实现?
二、锁的介绍
1、表锁、行锁
- 通过锁来管理不同事务对共享资源的并发访问
- 表锁与行锁的区别:
锁定粒度:表锁 > 行锁
加锁效率:表锁 > 行锁
冲突概率:表锁 > 行锁
并发性能:表锁 < 行锁 - InnoDB存储引擎只支持行锁,表锁是通过锁住所有行实现
2、InnoDB锁类型
- 共享锁(行锁,又称S锁):Shared Locks
又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁, 都能访问到数据,但是只能读不能修改。
select * from teachers WHERE id=1 LOCK IN SHARE MODE; commit/rollback
- 排它锁(行锁,又称X锁):Exclusive Locks
又称为写锁,简称X锁,排他锁不能与其他锁并存,如一个事务获取了一个数据行的排他 锁,其他事务就不能再获取该行的锁(共享锁、排他锁),只有该获取了排他锁的事务是可以对 数据行进行读取和修改,(其他事务要读取数据可来自于快照)
delete / update / insert 默认加上X锁 SELECT * FROM table_name WHERE ... FOR UPDATE commit/rollback
- 意向锁共享锁(表锁):Intention Shared Locks
表示事务准备给数据行加入共享锁,即一个数据行加共享锁前必须先取得该表的IS锁, 意向共享锁之间是可以相互兼容的 - 意向锁排它锁(表锁):Intention Exclusive Locks
表示事务准备给数据行加入排他锁,即一个数据行加排他锁前必须先取得该表的IX锁, 意向排它锁之间是可以相互兼容的
意向锁(IS、IX)是InnoDB数据操作之前自动加的,不需要用户干预,当事务想去进行锁表时,可以先判断意向锁是否存在,存在时则可快速返回该表不能 启用表锁
- 自增锁:AUTO-INC Locks
针对自增列自增长的一个特殊的表级别锁 - 记录锁 Record Locks (行算法锁)
锁住具体的索引项 当sql执行按照唯一性(Primary key、Unique key)索引进行数据的检索时,查询条件等值匹 配且查询的数据是存在,这时SQL语句加上的锁即为记录锁Record locks,锁住具体的索引项 - 间隙锁 Gap Locks(行算法锁)
锁住数据不存在的区间(左开右开) 当sql执行按照索引进行数据的检索时,查询条件的数据不存在,这时SQL语句加上的锁即为 Gap locks,锁住索引不存在的区间(左开右开) - 临键锁 Next-key locks (行算法锁)
锁住记录+区间(左开右闭) 当sql执行按照索引进行数据的检索时,查询条件为范围查找(between and、<、>等)并有数 据命中则此时SQL语句加上的锁为Next-key locks,锁住索引的记录+区间(左开右闭)
InnoDB行锁到底锁了什么
- InnoDB的行锁是通过给索引上的索引项加锁来实现的。
- 只有通过索引条件进行数据检索,InnoDB才使用行级锁,否则,InnoDB 将使用表锁(锁住索引的所有记录)
- 表锁:lock tables xx read/write;
三、利用锁解决事务并发问题
1、脏读问题
同一条数据被事务A查询,又被事务B修改数据,那么防止事务A读到事务B未提交的脏数据,我们就给事务B修改的数据加上排它锁(X锁):Exclusive Locks进行的锁定,防止事务A出现脏读。
2、不可重复读问题
同一条数据需要被事务A多次查询,其中又被事务B修改数据,那么防止事务A在第二次读取数据不一致,我们就给事务A读取的数据加共享锁(S锁):Shared Locks进行的锁定,防止事务A出现不可重复读。
3、幻读问题
当事务A需要多次查询一个范围数据时,其范围中又被事务B新增或者删除数据,防止事务A在第二次读取范围数据不一致,我们就给事务A读取的范围数据加上临键锁 Next-key,防止事务A出现幻读。
四、死锁介绍和死锁避免
1、死锁介绍
- 多个并发事务(2个或者以上);
- 每个事务都持有锁(或者是已经在等待锁);
- 每个事务都需要再继续持有锁;
- 事务之间产生加锁的循环等待,形成死锁。
2、死锁的避免
- 类似的业务逻辑以固定的顺序访问表和行。
- 大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
- 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概 率。
- 降低隔离级别,如果业务允许,将隔离级别调低也是较好的选择
- 为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添 加上锁(或者说是表锁)
来源:CSDN
作者:hekeyer
链接:https://blog.csdn.net/hekeyer/article/details/104562946