当前位置: 首页 > news >正文

MySQL并发事务访问相同记录

 概述

在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的 资源。为保证数据的一致性,需要对 并发操作进行控制 ,因此产生了 锁 。同时 锁机制 也为实现MySQL的各个隔离级别提供了保证。 锁冲突 也是影响数据库 并发访问性能 的一个重要因素。所以锁对数据库而 言显得尤其重要,也更加复杂。

读-读情况

读-读 情况,即并发事务相继 读取相同的记录 。读取操作本身不会对记录有任何影响,并不会引起什么 问题,所以允许这种情况的发生。

写-写情况

写-写 情况,即并发事务相继对相同的记录做出改动。 在这种情况下会发生 脏写 的问题,任何一种隔离级别都不允许这种问题的发生。所以在多个未提交事务 相继对一条记录做改动时,需要让它们 排队执行 ,这个排队的过程其实是通过 锁 来实现的。这个所谓 的锁其实是一个 内存中的结构 ,在事务执行前本来是没有锁的,也就是说一开始是没有 锁结构 和记录进 行关联的,如图所示:

当一个事务想对这条记录做改动时,首先会看看内存中有没有与这条记录关联的 锁结构 ,当没有的时候 就会在内存中生成一个 锁结构 与之关联。比如,事务 T1 要对这条记录做改动,就需要生成一个 锁结构与之关联:

小结几种说法:

不加锁意思就是不需要在内存中生成对应的 锁结构 ,可以直接执行操作。

获取锁成功,或者加锁成功 意思就是在内存中生成了对应的 锁结构 ,而且锁结构的 is_waiting 属性为 false ,也就是事务 可以继续执行操作。

获取锁失败,或者加锁失败,或者没有获取到锁意思就是在内存中生成了对应的 锁结构 ,不过锁结构的 is_waiting 属性为 true ,也就是事务 需要等待,不可以继续执行操作。  

读-写或写-读情况 

读-写 或 写-读 ,即一个事务进行读取操作,另一个进行改动操作。这种情况下可能发生 脏读 、 不可重 复读 、 幻读 的问题。

各个数据库厂商对 SQL标准 的支持都可能不一样。比如MySQL在 REPEATABLE READ 隔离级别上就已经 解决了 幻读 问题。

并发问题的解决方案

怎么解决 脏读 、 不可重复读 、 幻读 这些问题呢?其实有两种可选的解决方案:

方案一

读操作利用多版本并发控制( MVCC ,下章讲解),写操作进行 加锁 。

普通的SELECT语句在READ COMMITTED和REPEATABLE READ隔离级别下会使用到MVCC读取记录。

         在 READ COMMITTED 隔离级别下,一个事务在执行过程中每次执行SELECT操作时都会生成一 个ReadView,ReadView的存在本身就保证了 事务不可以读取到未提交的事务所做的更改 ,也就 是避免了脏读现象;

        在 REPEATABLE READ 隔离级别下,一个事务在执行过程中只有 第一次执行SELECT操作 才会 生成一个ReadView,之后的SELECT操作都 复用 这个ReadView,这样也就避免了不可重复读 和幻读的问题。

方案二

读、写操作都采用 加锁 的方式。  

小结对比发现:

采用 MVCC 方式的话, 读-写 操作彼此并不冲突, 性能更高 。 采用 加锁 方式的话, 读-写 操作彼此需要 排队执行 ,影响性能。 一般情况下我们当然愿意采用 MVCC 来解决 读-写 操作并发执行的问题,但是业务在某些特殊情况 下,要求必须采用 加锁 的方式执行。

相关文章:

  • 利用UART串口实现数据的收发
  • 虚幻引擎5 C++游戏开发教程
  • 【GNN报告】GNN可解释性 基于几何与拓扑特性的图学习
  • Hadoop3 - HDFS 介绍及 Shell Cli 操作
  • Java~数据结构(三)~栈和队列(Stack\Queue\Deque的常用方法和模拟实现一个栈和队列等)
  • 股票API下单接口是怎样传入交易数据的?
  • 【C++初阶】C++入门篇(二)
  • 点云LAS格式分析
  • 关于我的家乡html网页设计完整版,10个以家乡为主题的网页设计与实现
  • 有营养的算法笔记(二)
  • 10.5 - 每日一题 - 408
  • 递归、分治算法刷题笔记
  • 微服务架构秘籍:SpringCloud+SpringCloud Alibaba,全网疯传
  • HDLbits exercises 10(LATCHES AND FLIP-FLOPS后半部分题)
  • MySQL经典练习题+解题思路(四)
  • 自己简单写的 事件订阅机制
  • Android Volley源码解析
  • Debian下无root权限使用Python访问Oracle
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • HashMap ConcurrentHashMap
  • js作用域和this的理解
  • Linux各目录及每个目录的详细介绍
  • redis学习笔记(三):列表、集合、有序集合
  • unity如何实现一个固定宽度的orthagraphic相机
  • Vue2 SSR 的优化之旅
  • XForms - 更强大的Form
  • 大型网站性能监测、分析与优化常见问题QA
  • 我这样减少了26.5M Java内存!
  • 小程序01:wepy框架整合iview webapp UI
  • Prometheus VS InfluxDB
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • ​secrets --- 生成管理密码的安全随机数​
  • ​决定德拉瓦州地区版图的关键历史事件
  • (3)nginx 配置(nginx.conf)
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (附源码)ssm码农论坛 毕业设计 231126
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (十三)Flask之特殊装饰器详解
  • (一)UDP基本编程步骤
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)大型网站的系统架构
  • ./configure,make,make install的作用
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .net项目IIS、VS 附加进程调试
  • @CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思
  • @Documented注解的作用
  • @staticmethod和@classmethod的作用与区别
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • [Android Studio] 开发Java 程序
  • [Android]通过PhoneLookup读取所有电话号码
  • [AutoSar]BSW_OS 02 Autosar OS_STACK