IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 数据库事物概览 -> 正文阅读

[大数据]数据库事物概览

ACID

原子性:当客户想进行多次写入,但在一些写操作处理完之后出现故障的情况。例如进程崩溃,网络连接中断,磁盘变满或者某种完整性约束被违反。如果这些写操作被分组到一个原子事务中,并且该事务由于错误而不能完成(提交),则该事务将被中止,并且数据库必须丢弃或撤消该事务中迄今为止所做的任何写入。
一致性对数据的一组特定陈述必须始终成立。即不变量(invariants)。例如,在会计系统中,所有账户整体上必须借贷相抵。如果一个事务开始于一个满足这些不变量的有效数据库,且在事务处理期间的任何写入操作都保持这种有效性,那么可以确定,不变量总是满足的。
隔离性:同时执行的事务是相互隔离的:它们不能相互冒犯。传统的数据库教科书将隔离性形式化为可序列化(Serializability),这意味着每个事务可以假装它是唯一在整个数据库上运行的事务。数据库确保当事务已经提交时,结果与它们按顺序运行(一个接一个)是一样的,尽管实际上它们可能是并发运行的。
持久性:是一个承诺,即一旦事务成功完成,即使发生硬件故障或数据库崩溃,写入的任何数据也不会丢失。

隔离级别与异常现象

ANSI SQL-92 提出了最经典的隔离级别定义,包括读未提交(Read Uncommitted)、读提交(Read Committed)、可重复读(Repeatable Read)和可序列化(Serializable)。
在这里插入图片描述

Dirty Write

如果先前的写入是尚未提交事务的一部分,又会发生什么情况,后面的写入会覆盖一个尚未提交的值?这被称作脏写(dirty write),任何隔离级别都应该防止脏写的产生

以一个二手车销售网站为例,Alice和Bob两个人同时试图购买同一辆车。购买汽车需要两次数据库写入:网站上的商品列表需要更新,以反映买家的购买,销售发票需要发送给买家。在下图中,销售是属于Bob的(因为他成功更新了商品列表),但发票却寄送给了爱丽丝(因为她成功更新了发票表)。
在这里插入图片描述

Dirty Read

Dirty Read 的解释是一个事物读取到还未提交的事务的写入内容就算发生了 Dirty Read。

在这里插入图片描述

Repeatable Read

Repeatable Read 指的是两次读操作读到了不同的数据。

在这里插入图片描述
如例 9 所示,在严格解释下需要进行完整的两次读取;但是扩大解释则认为在一个事务读了某个 key 之后,如果读事务还没提交,有事务写这个 key 成功了就可能出现异常,换句话说,读请求 应该 阻塞写请求(在Serializable隔离级别下就是这么做的)

Phantom Read

Phantom Read 指的是,在一个事物中,前期通过读取操作(select)获得的信息,不足以支撑我最后的写操作(insert,update,delete)。根本原因在于 MySQL 读的时候是快照读,但是写的时候是写最新版本。

在这里插入图片描述
右边session看到明明表是空的,但是插入的时候却报错 (1062, "Duplicate entry '1' for key 'test.PRIMARY'"),存在重复主键。
在这里插入图片描述
右边session看到明明表是空的,但是却可以update成功。

业务程序员的错误

指业务程序员使用了不合适的隔离级别来操纵数据库,导致得到的最终结果不符合业务的一致性(consistency)。

Read Skew

错误的使用了会产生 Repeatable Read 的隔离级别(Read Uncommitted,Read Committed)

爱丽丝在银行有1000美元的储蓄,分为两个账户,每个500美元。现在一笔事务从她的一个账户中转移了100美元到另一个账户。如果她在事务处理的同时查看其账户余额列表,不幸地在转账事务完成前看到收款账户余额(余额为500美元),而在转账完成后看到另一个转出账户(已经转出100美元,余额400美元)。对爱丽丝来说,现在她的账户似乎只有900美元——看起来100美元已经消失了。
在这里插入图片描述

Lost Update

错误的使用了非 Serializable 的隔离级别

(假设数据库中没有自增操作)每个客户端需要读取计数器的当前值,加 1 ,再回写新值。下图中,因为发生了两次增长,计数器应该从42增至44;但由于竞态条件,实际上只增至 43 。
在这里插入图片描述
我认为这是由于幻读造成的(明明我看到的就是42呀,我就把它加一再写回去就行了嘛,但是你看到的信息,不能支撑你后续的写入逻辑)。

Write Skew

错误的使用了非 Serializable 的隔离级别

首先,想象一下这个例子:你正在为医院写一个医生轮班管理程序。医院通常会同时要求几位医生待命,但底线是至少有一位医生在待命。医生可以放弃他们的班次(例如,如果他们自己生病了),只要至少有一个同事在这一班中继续工作。
现在想象一下,Alice和Bob是两位值班医生。两人都感到不适,所以他们都决定请假。不幸的是,他们恰好在同一时间点击按钮下班。下图说明了接下来的事情。
在这里插入图片描述
在两个事务中,应用首先检查是否有两个或以上的医生正在值班;如果是的话,它就假定一名医生可以安全地休班。由于数据库使用快照隔离,两次检查都返回 2 ,所以两个事务都进入下一个阶段。Alice更新自己的记录休班了,而Bob也做了一样的事情。两个事务都成功提交了,现在没有医生值班了。违反了至少有一名医生在值班的要求。

再看一个例子,即 T1 尝试把 x 的值赋给 y,T2 尝试把 y 的值赋给 x,如果这两个事务 Serializable 的执行,那么在结束之后 x 和 y 应该拥有一样的值,但是在 Write Skew 中,并发操作使得他们的值互换了。
在这里插入图片描述

可以将写入偏差视为丢失更新问题的一般化。如果两个事务读取相同的对象,然后更新其中一些对象(不同的事务可能更新不同的对象),则可能发生写入偏差。在多个事务更新同一个对象的特殊情况下,就会发生丢失更新

避免 Lost Update & Write Skew

在 Serializable 的隔离级别中进行操作当然避免,但是如何在 Repeatable Read 隔离级别中避免 Lost Update & Write Skew。

假设有A、B两个用户同时各购买一件 id=1 的商品,用户A获取到的库存量为 1000,用户B获取到的库存量也为 1000,用户A完成购买后修改该商品的库存量为 999,用户B完成购买后修改该商品的库存量为 999,此时库存量数据产生了不一致。(类似上面计数器的例子)

有两种解决方案:

悲观方案:每次获取商品时,对该商品通过 select for update 加排他锁,同时进行当前读。也就是在用户A获取获取 id=1 的商品信息时对该行记录加锁,期间其他用户阻塞等待访问该记录。
(如果使用普通的读,会得到一致性的结果,如果使用了加锁的读,就会读到“最新的”“提交”读的结果。本身,可重复读和提交读是矛盾的。在同一个事务里,如果保证了可重复读,就会看不到其他事务的提交,违背了提交读;如果保证了提交读,就会导致前后两次读到的结果不一致,违背了可重复读。可以这么讲,InnoDB提供了这样的机制,在默认的可重复读的隔离级别里,可以使用加锁读去查询最新的数据。See:http://blog.sina.com.cn/s/blog_499740cb0100ugs7.html

begin;
select * from goods where id = 1 for update;
update goods set stock = stock - 1 where id = 1;
commit;

乐观方案:每次获取商品时,不对该商品加锁。在更新数据的时候需要比较程序中的库存量与数据库中的库存量是否相等,如果相等则进行更新,反之程序重新获取库存量,再次进行比较,直到两个库存量的数值相等才进行数据更新。乐观锁适合读取频繁的场景。

#不加锁获取 id=1 的商品对象
select * from goods where id = 1

begin;
#更新 stock 值,这里需要注意 where 条件 “stock = cur_stock”,只有程序中获取到的库存量与数据库中的库存量相等才执行更新
update goods set stock = stock - 1 where id = 1 and stock = cur_stock;
commit;

参考

https://juejin.cn/post/6844903927536844808
https://juejin.cn/post/6844903952165634061
https://www.jianshu.com/p/eb3f56565b42
http://blog.sina.com.cn/s/blog_499740cb0100ugs7.html
https://blog.csdn.net/taylor_tao/article/details/7063639
https://www.jianshu.com/p/cef49aeff36b
https://blog.csdn.net/claram/article/details/54023216
https://vonng.gitbooks.io/ddia-cn/content/ch7.html
https://pingcap.com/zh/blog/take-you-through-the-isolation-level-of-tidb-1

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-12-09 11:45:16  更:2021-12-09 11:47:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:34:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码