计算机协调多个进程或线程并发访问某一资源的机制
防止多事务并发造成数据不统一,避免脏写、脏读、不可重复读、幻读等问题
脏写:事务A和事物B同时改一行数据,最后的更新覆盖了其他事务所做的更新
脏读:事务A读取到了事务B已经修改但尚未提交的数据
不可重复读:事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性
幻读:事务A读取到了事务B提交的新增数据,不符合隔离性
// 查看当前数据库的事务隔离级别
show variables like 'tx_isolation';
// 设置事务隔离级别
set tx_isolation = 'REPEATABLE-READ';
事务B可以读到事务A未提交的数据
事务B可以读到事务A提交的数据
事务B连接之后,读到的一直是连接开始的数据
可重复读的隔离级别下使用了MVCC(multi-version concurrency control)机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
事务A操作未提交,事务B查询将一直处于等待状态
并发性很低,开发中很少会用到
作用范围:库(database)
实现层:SQL layer层
影响:整个库处于只读状态,所有更新操作都将阻塞
使用场景:全库逻辑备份(会影响业务运行,正常业务数据无法写入,无法同步,不推荐)
// 加锁
flush tables with read lock;
// 释放锁,或者断开事务连接,自动释放全局锁
unlock tables;
作用范围:表
实现层:SQL layer层
优点:开销小、加锁快,不会出现死锁
缺点:锁定粒度大,发生锁冲突的概率最高,并发度最低
场景:一般用在整表数据迁移
查看表锁状态变量
show status like 'table%';
- table_locks_immediate:产生表级锁定的次数;
- table_locks_waited:出现表级锁定争用而发生等待的次数
表锁两种表现形式:表共享读锁(Table Read Lock)、表独占写锁(Table Write Lock)
// 手动增加表锁
lock table tblname read(write);
// 查看表锁情况
show open tables;
// 删除表锁
unlock tables;
读锁影响:
1、自身和其他事务都能读
2、自身无法读取其他表,其他事务可以
3、自身写入或更新表会报错,其他事务将处于等待状态
写锁影响:
自身查询和写入都没问题,其他事务处于等待状态
不需要显示使用,访问一个表的时候会自动加上,保证读写的正确性
增删改查操作加MDL读锁,表结构变更操作加MDL写锁
读锁之间不互斥
读写、写写之间互斥
mysql内部使用,不需要用户干预
意向锁和行锁可以共存
作用:为了全表更新数据时的性能提升,协调行锁与表锁的关系,判断表中有没有行锁
涉及AUTO_INCREMENT列的事务性插入操作时产生
作用范围:某行 或者 行之间的间隙
实现层:存储引擎
InnoDB行锁:通过给索引上的索引项加锁来实现的,只有通过索引条件检索的数据才能使用,其他将使用表锁
优点:锁定粒度最小,发生锁冲突的概率最低,并发度最高
缺点:开销大、加锁慢、会出现死锁
// 查看行锁争夺情况
show status like 'innodb_row_lock%';
Innodb_row_lock_current_waits: 当前正在等待锁定的数量
Innodb_row_lock_time: 从系统启动到现在锁定总时间长度(等待总时长)
Innodb_row_lock_time_avg: 每次等待所花平均时间(等待平均时长)
Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花时间
Innodb_row_lock_waits:系统启动后到现在总共等待的次数(等待总次数)
按照锁定范围划分:
锁定索引中一条记录,锁住的是索引,而不是记录本身
// 记录共享锁
select * from tblname where id = 1 lock in share mode;
// 记录排他锁
select * from tblname where id = 1 for update;
锁住一个索引区间(开区间,不包括双端端点)
要么锁住索引记录中间的值,要么锁住第一个索引记录前面的值或者最后一个索引记录后面的值。
作用:防止幻读,保证索引间不会被插入数据
在可重复读隔离级别下才会生效
select * from tblname where id > 4 for update;
索引记录上的记录锁和在索引记录之前的间隙锁的组合(间隙锁+记录锁)(左开右闭区间)
做insert操作时添加的对记录id的锁。
按功能划分:
共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
select * from tblname where ... lock in share mode;
排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
select * from tblname where ... for update;
加了S锁的记录,允许其他事务再加S锁,不能再加X锁
select ... lock in share mode
加了X锁的记录,不允许其他事务再加锁
select ... for update
两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源。锁定之后,双方都需要等待对方释放锁,同时又持有对方需要的锁,则陷入死循环。
1、多个事务试图以不同的顺序锁定资源
2、多个事务同时锁定同一个资源
和存储引擎相关
set tx_isolation='repeatable-read';
Session_1执行:select * from account where id=1 for update;
Session_2执行:select * from account where id=2 for update;
Session_1执行:select * from account where id=2 for update;
Session_2执行:select * from account where id=1 for update;
1、检测到死锁的循环依赖,立即返回一个错误
2、当查询的时间达到锁等待超时的设定后放弃锁请求(不好)
3、将持有最少行级排他锁的事务进行回滚
使用–single-transaction参数,利用mvcc提供一致性视图
不会影响业务的正常运行
使用–lock-all-tables参数