陪玩系统开发,事务隔离级别和锁影响数据一致性
陪玩系统开发,事务隔离级别和锁影响数据一致性
最近陪玩系统开发的生产环境零星出现了几笔脏数据,即同一业务编号出现了两条数据(我们系统中唯一性并未依靠于数据库的索引)。明明代码中已经加锁了, 还出现这样的问题,经定位,发现是事务的隔离性,导致第二个事务看不到第一个事务的数据,从而导致数据重复。
业务伪代码
// 省略了一些必要的异常处理。 @Transactional public void saveAndComplete(T entity) { lock.lock(); code = repository.findByCode(entity.getCode()); if (code.isEmpty()) { repository.save(entity); } this.Complete(entity.getCode()); lock.unlock(); }
代码很简单,有一个saveAndComplete方法,用来保存实体,并完成任务,并用Spring的事务管理器管理事务,当Complete方法抛出异常时,进行回滚。但是如果数据库事务隔离级别为读已提交及以上,在高并发量下,还是会出现重复数据。
原因分析
事务t1启动。
事务t2启动。
线程t1获取锁,成功。
事务t2获取锁,失败,并等待。
线程t1检查是否存在entity1,发现不存在,保存数据。
线程t1释放锁。
事务t1提交。
事务t2获取锁。
事务t2 检查是否存在entity1,发现不存在,保存数据。
事务t2 释放锁。
事务t2 提交。
主要原因就在步骤9,由于InnoDB默认的隔离级别是可重复读,所以即使事务t1已经将entity1插入数据库,事务t2也是看不到的,所以会出现重复数据。
问题解决
问题解决起来也不难,只要保证事务t2在事务t1结束之后再开始即可,即插入数据这个动作的事务线性化。代码如下
// 省略了一些必要的异常处理。 public void saveAndComplete(T entity) { lock.lock(); transactionManager.getTransaction(); // 先获取锁,再开启事务 code = repository.findByCode(entity.getCode()); if (code.isEmpty()) { repository.save(entity); } this.Complete(entity.getCode()); transactionManager.commit(); // 先提交事务,最后释放锁。 lock.unlock(); }
以上就是陪玩系统开发,事务隔离级别和锁影响数据一致性, 更多内容欢迎关注之后的文章
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2023-07-20 直播系统搭建,java实现 图片转ico
2023-07-20 直播开发app,Java修改图片大小尺寸图片缩放
2023-07-20 视频直播源码,实现pdf在线预览并且自定义预览框高度
2022-07-20 直播系统源码,登录时自动填取获得的验证码
2022-07-20 直播app系统源码,给视频背景添加上水印
2022-07-20 短视频带货源码, 文本上下滚动和图片闪烁