数据库并发场景

所有系统的并发场景都是三种,对于数据库而言为:

读-读:不存在任何问题,也不需要并发控制。

读-写:有线程安全问题,可能会造成事务隔离性问题,也就是脏读,不可重复读,幻读。

写-写:有线程安全问题,会存在更新丢失问题:第一类更新丢失(回滚丢失),第二类更新丢失(覆盖丢失)。

事务隔离级别

隔离级别:串行化SERIALIZABLE、可重复读(REPEATABLE READ)、读提交(READ COMMITTED)、读未提交(READ UNCOMMITTED)

可重复读(REPEATABLE READ):当前正在执行事务产生的数据变化不能被外部看到,也就是说,如果用户在另外一个事务中执行同条 SELECT 语句数次,结果总是相同的。

读提交(READ COMMITTED):处于 READ COMMITTED 级别的事务可以看到其他事务对数据的修改。也就是说,在事务处理期间,如果其他事务修改了相应的表,那么同一个事务的多个 SELECT 语句可能返回不同的结果。

读未提交(READ UNCOMMITTED):处于这个隔离级的事务可以读到其他事务还没有提交的数据。如果这个事务使用其他事务不提交的变化作为计算的基础,然后那些未提交的变化被它们的父事务撤销,就会导致大量的数据变化。

查看隔离级别:

读未提交(READ UNCOMMITTED)

用一个例子来演示读未提交的隔离级别。设置当前会话的隔离级别,并准备一张staffs表:

set session transaction isolation level READ UNCOMMITTED;

1、启动事务A:

BEGIN;
select * from staffs where id =1;

2、启动事务B:

BEGIN;
select * from staffs where id =1;
update staffs set age=11 where id=1;

事务B执行完update动作后不commit提交,在事务A中继续查询id=1的值,如下所示:

两次读到的数据不一致,事务A已经读到了别的事务未提交的修改,这个就是脏读。读未提交还会产生不可重复读。

读提交(READ COMMITTED)

在读提交的隔离级别下,当事务B修改完数据尚未提交时,事务A是无法读取到修改的数据的。当事务B提交事务后,事务A才可以看到修改的结果。

读可重复(REPEATABLE READ)

当事务B提交后,事务A查询的结果依然是事务A开启时读到的数据,这就是所谓的可重复读,也就是说事务开启时读到的数据,在事务提交前,是一致的,不会因为外面事务的修改提交而改变开启事务前读到的值。

可重复读会有幻读现象,比如事务A读取某唯一索引不存在,但是插入时显示异常失败,原因是其他事务插入的数据对事务A不可见。可以使用select ..for update;间隙锁解决幻读问题。

串行化

串行化不允许多个事务并行操作同一行数据,开启事务A未提交前事务B会阻塞。

视图

不同的隔离级别主要是为了提高数据库的并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。

不同隔离级别在select读时表现不同,主要是生成Read View(读视图)的策略不同。

Read View是事务进行快照读操作的时候生产的读视图,在当前事务执行快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID。事务ID默认单调递增。查询不会新增事务ID,只有DML才会导致事务ID增加。

当前读

select lock in share mode(共享锁),select for update;update,insert,delete(排他锁);这些操作都是一种当前读,当前读读取的记录都是目前数据库中最新的版本。读取时还要保证其它并发事务不能修改当前记录,所以会对读取数据加锁。

快照读

像不加锁的select操作就是快照读,即不加锁的非阻塞读。串行级别下的快照读会加锁,退化成当前读。

数据库隐式字段

数据库每行记录除了业务字段外,还有数据库隐式定义的几个字段:

DB_ROW_ID:隐藏自增ID,如果表没有定义主键,会使用该ID。
DB_TRX_ID:最近修改的事务ID,记录创建这条记录以及最后一次修改该记录的事务的ID。
DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本(undo log日志)。
DELETED_BIT:delete操作跟truncate/drop不一样,仅使用该flag标记逻辑删除。

Undo log记录形式

对于insert操作,undo日志仅记录新数据的主键,回滚时直接删除;

对于delete/update操作,undo日志需要记录旧数据整行内容,回滚时直接恢复;

MVCC多版本并发控制就是基于undo log实现,undo log简化理解为多个事务对某行数据写操作的记录链,类似写时复制。示例:

1、初始事务往 persion表中插入了一条新记录,记录如下,name = a1,age = 11;隐式主键 = 1,事务ID和回滚指针此时都为 NULL;

2、事务1对该行的name作出修改,改为a2;

2.1 在 事务1 修改该行记录数据的同时,数据库会先对该行加排他锁(InnoDB引擎会自动对DML语言影响的记录上写锁|独占锁)。

2.2 上锁完毕后,将该行数据拷贝到 undo log 中,作为旧记录,即在 undo log 中有当前行的拷贝副本。

2.3 拷贝完毕后,修改该行的 name 为 a2,并且修改隐藏字段的事务ID为当前 事务1的ID,这里事务ID默认是从1开始递增,回滚指针指向拷贝到 undo log 的副本记录,即表示我的上一个版本就是他。

2.4 事务提交后,释放锁。

3、又来一个事务2修改persion表的同一行记录,将age项修改为 22岁;在事务2修改该行数据之前,数据库继续给他上排他锁。

上锁完毕之后,把该行数据拷贝到 undo log 中,作为旧记录,发现操作的这行记录已经有undo log 的记录了,那么最新的旧数据作为链表的表头,插在这行记录的 undo log 日志的最前面。

修改该行age为22岁,并且修改隐藏字段的事务ID为当前事务2的ID,那就是2,回滚指针指向刚刚拷贝到 undo log 的副本记录。

事务提交,释放锁。

undo log 的链首就是最新的旧记录,尾部是最旧的记录。数据库的purg线程会定期清理掉已提交的事务记录,使undo log重复使用。

Read View读视图

Read View 有三个全局参数:

trx_list:未提交事务 ID 列表,用来维护 Read View 生成时刻系统正处于活跃状态的事务ID。

up_limit_id:记录 trx_list 事务ID列表中 最小的ID,也就是最初修改该记录的事务。

low_limit_id:Read View生成时刻数据库尚未分配的下一个事务ID,也就是当前最大事务ID + 1。

以RR级别和RC级别来分析,开启事务的时候开启一个 Read View,假定当前事务ID = 10,trx_list为(4,8, 10),因为当前事务10正在执行,所以自己也活跃,所以此时 up_limit_id=4,low_limit_id=11。

如果读到一个数据的 事务ID =3,小于 活跃列表的最小值(up_limit_id=4),可见;如果读到一个数据的 事务ID = 12,大于low_limit_id,不可见,需要根据回滚指针从undo log中找到小于up_limit_id的版本,或者不在活跃事务列表trx_list中的版本。

RR级别和RC级别的区别是:

RR级别开启事务的时候开启一个Read View,并且整个事务过程中一直使用这个视图;RC级别在每次读取时都使用最新的视图,因此会读到已提交事务的修改信息。

-写冲突

目前数据库基本不会出现第一类更新丢失,快照读是第二类更新丢失的一个主要原因,需要将一致性非锁定读替换为一致性锁定读,使用悲观锁/乐观锁解决。

总结:

MVCC可以解决多版本读写冲突加锁,而写写冲突还是需要锁来保证。

Mysql并发读写解决方案分析--MVCC相关推荐

  1. mysql并发写入性能分析

    目前,在很多OLTP场景中,MySQL数据库都有着广泛的应用,也有很多不同的使用方式.从数据库的业务需求.架构设计.运营维护.再到扩容迁移,不同的MySQL架构有不同的特点,适应一定的业务场景,或者解 ...

  2. mysql会对同时读取加锁吗_程序员经典面试题,MySQL并发读写的时候,都是需要加锁的么?...

    这是一道经典的程序员面试题,在Mysql中,如果有多个事务同时访问同一行数据,那么需要加锁么?我们都知道,在Mysql中有行锁,如果有多个事务同时修改同一行数据,那么需要加锁来防止并发问题.那么,如果 ...

  3. mysql 并发_MySQL的并发控制与加锁分析

    本文主要是针对MySQL/InnoDB的并发控制和加锁技术做一个比较深入的剖析,并且对其中涉及到的重要的概念,如多版本并发控制(MVCC),脏读(dirty read),幻读(phantom read ...

  4. mvcc原理_MVCC原理探究及MySQL源码实现分析

    沃趣科技数据库专家  董红禹 MVCC原理探究及MySQL源码实现分析 数据库多版本读场景 session 1 session 2 select a from test; return a = 10 ...

  5. mysql并发更新数据,多用户并发修改数据解决方案。

    mysql并发更新数据,多用户并发修改数据解决方案. 在系统中,有一些如余额.资产.积分的数据,是要保证数据一致性的.如,一个人使用两个设备同时进行消费操作,如何保证数据一致性的问题. 我们一起来思考 ...

  6. php中并发读写文件冲突的解决方案(文件锁应用示例)

    php中并发读写文件冲突的解决方案(文件锁应用示例) 参考文章: (1)php中并发读写文件冲突的解决方案(文件锁应用示例) (2)https://www.cnblogs.com/wellsoho/p ...

  7. 高并发网络架构解决方案分析

    1:html静态化 2:图片服务器分离 3:数据库集群 4:缓存 5:负载均衡 大型高并发高负载网站的系统架构 我在Cernet做过拨号接入平台的搭建,而后在Yahoo3721负载搜索引擎前端平台开发 ...

  8. mysql myisam写入性能_(转)innodb 与 myisam 读写性能分析

    前提: mysql在5.0之前,读写性能相差很大,读性能:myisam 很强 mysql在5.0之后,差距不是很大 http://www.taobaodba.com/ 由于近期有个项目对系统性能要求很 ...

  9. mysql高并发秒杀_高并发秒杀解决方案(转载)

    今天王总又给我们上了一课,其实mysql处理高并发,防止库存超卖的问题,在去年的时候,王总已经提过:但是很可惜,即使当时大家都听懂了,但是在现实开发中,还是没这方面的意识.今天就我的一些理解,整理一下 ...

最新文章

  1. CSS概念,引入,选择器
  2. 华为数据之道_华为构筑产业数字化的太极之道
  3. VIM中常用的替换模式总结
  4. JavaScript 是如何工作的:解析、抽象语法树(AST)+ 提升编译速度5个技巧
  5. C# dataGridView控件实用属性及事件总结
  6. 我在深圳,但是家里托人在老家找了一份工作
  7. Numpy重要模块——linalg线性代数详细参数及演示
  8. dotnet 入门到放弃 使用 .NET Core 卸载工具
  9. 《深入浅出MFC》读书笔记
  10. 2019年计算机考研408历年真题2009-2019下载免费下载
  11. 2019.07.23--运用三W法则初步学习SpringCloud基础知识
  12. directX11 软件包下载与配置
  13. 【新手入门.考试高频】Java中“一个类声明的两个对象如果有相同的引用,二者就有相同的变量”的理解
  14. Word里能放电影吗?
  15. 算法与数据结构之带头结点和不带头结点单链表存在的问题
  16. 小程序 JSON.stringify() 和 JSON.parse() 的使用
  17. linux composer root,Composer在Windows和Linux的安装和使用
  18. SublimeText设置成中文简体
  19. WinDBG命令概览
  20. java实现报时助手_蓝桥杯 基础练习 报时助手

热门文章

  1. STM32F103C8T6封装引脚图
  2. 电信光纤无线路由器(光猫)的设置方法
  3. python绘制气象等值线图_气象要素场等值线图自动绘制
  4. 天大《应用统计学》大作业期末考核
  5. Excel 单元格适配
  6. 04.TFT_RGB接口时序分析
  7. ICC Profile
  8. MySQL数据类型----布尔型,时间型,枚举型的简单介绍
  9. 风影墙纸,一天看N回。
  10. HBase-拆分合并和调优参考