关于mysql锁的两个例子
版本:mysql5.5.52
存储引擎:InnoDB
隔离级别:READ-COMMITTED
示例一:
事务1:左图 事务2:右图
1、
事务2中属于快照读,基于多版本的并发控制协议——MVCC,读取的是记录可见版本,不用加锁,事务1属于当前读,加排它锁,因此事务1虽然未提交,事务2依然可以执行。快照读是mysql InnoDB存储引擎下,隔离级别为READ COMMITTED和REPEATABLE READ时,select语句默认的读取模式。
2、
事务1属于当前读,加排它锁,事务2的读取操作也是需要排他锁的,因此读取被阻塞,导致超时,直到事务1提交后,事务2才能读取:
3、
事务1属于当前读,加排它锁,但由于隔离级别为READ-COMMITTED,不加gap锁,依然可以插入,如果将隔离级别换成REPEATABLE READ,第一次插入操作被阻塞,直到事务1提交时,插入操作才执行:
gap就是索引树中插入新记录的空隙,相应的gap lock就是加在gap上的锁,主要是为了防止幻读,只在REPEATABLE READ或以上的隔离级别下的特定操作才会取得gap lock。
4、
对于事务1开启后在事务2中插入的记录,由于没有加排它锁,可以直接删除:
开启前已存在的记录,在事务1中加了排它锁,需等待事务1提交才能在事务2中删除:
示例二:
有一个后台的定时任务,定时向第三方发出状态改变请求,同时改变本地数据表的状态,但这个状态是否改变成功是需要第三方确认的,确认的方式是第三方以http请求的形式返回一个处理结果标志(成功或者失败),如果请求没有响应,则重复请求多次,直到我方响应。伪代码如下:
步骤一
我方发送状态改变请求:
@Transaction
public void sendChange(int id){
HttpUtils.send(id,"change");
statusDao.update(id,"pendSuccess");
relatedPeopleDao.update(id,"pendFinishRequest");
}
步骤二
我方响应第三方返回的处理结果(方法被web层调用):
@Transaction
public void doResponse(int id, String resultStatus){
relatedPeopleDao.update(id,resultStatus);
statusDao.update(id,resultStatus);
}
这个程序大部分情况是可以正常运行的,因为第三方返回处理结果有一段更长的网络延时,但是否存在这种可能,在方法sendChange开始执行 relatedPeopleDao.update(id,"pendFinishRequest")
这段代码的时候, 第三方很快返回了处理结果,relatedPeopleDao.update(id,resultStatus)已经执行且持有related_people表相关记录的锁,同时等待status表的锁被释放,但是此时sendChange的一系列操作尚未提交数据库,status的相关记录表仍被事务1持有,两个事务同时持有对方的资源同时在等待对方释放相关的锁,这就产生了死锁现象。
解决方法之一是在执行doResponse操作之前先检查下related_people表相关记录的状态是否处于合适状态,状态检查是一个普通的select操作,数据库隔离级别为读已提交,因此,如果步骤一中事务未提交,则不会读取到其改变的状态,提交后才能读取到。
@Transaction
public void doResponse(int id, String resultStatus){
if(relatedPeopleDao.isPendFinishRequest(id)){
relatedPeopleDao.update(id,resultStatus);
statusDao.update(id,resultStatus);
}
}
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- AsyncTask记录
- spring cloud gateway跨域冲突功能的开发
- Spring同时集成JPA与Mybatis
- Qt音视频开发10-ffmpeg控制播放
- 拿好了!Linux 运维必备的 13 款实用工具!
- 自制CA证书设置ssl证书
- MySQL数据迁移TcaplusDB实践
- TKE之初识容器探测器
- 2.3.2 JDK动态代理 -《SSM深入解析与项目实战》
- mac设备安装nginx注意事项
- 《研发运营安全白皮书(2020年)》深度解读:全生命周期安全体系将是未来趋势
- 深度学习故障诊断:残差收缩网络 Residual Shrinkage Networks
- Java基于SSM的个人博客系统(源码 包含前后台)
- 聊聊RespServer
- Spring Boot系列之读取配置