在数据库中新建一个字段并且设置为索引列,还有删除整张表的数据,类似这些操作都是一系列操作的组合,执行后不能出现中间状态,也就是不会出现新建了字段却不是索引的情况,也不会出现只有一部分数据被删除的情况。这种保证是事务在发挥作用,虽然我们没有使用begin-transaction-commit来执行命令。

既然事务是一系列操作的组合,那两个事务的多个操作如何正确顺序执行和如何高效执行就是关键了。这就要说说事务的ACID原则了,ACID指的是原子性、一致性、隔离性、持久性。

假设有这么一个场景,用户A的初始余额是100元,用户B的初始余额是0元,用户A需要向用户B转账100元。这个场景事实上是分二步执行的,第一步是扣除用户A账号上的100元,第二步是给用户B账号的余额增加100元。最终状态是用户A余额为0元,用户B的余额为100元。

不过,在执行扣除和增加这两步时随时可能发生错误。比如业务属性不匹配,用户B的账号有敏感操作被冻结了,无法更新,所以要恢复到初始状态。又比如系统崩溃了,所以系统重启时要首先进入安全模式,已提交的事务要继续完成,未提交的事务要取消掉。这样才能保证事务操作要么全部成功,要么全部失败。

那如何恢复到初始状态或者取消未提交的事务呢?

执行操作前把之前的值备份下来,不就可以借助备份进行递向操作了嘛?没错,在数据库的体现就是Undo log回滚段。

前面描述的事务场景可能过于简单,我们考虑这么一件事,用户C在刚才的事务执行过程中给用户B成功转入了300元,也就是说同时有多个事务在执行。不幸的是,刚才的事务被回滚了,用户B的余额最终被更新成了0元。后果就是用户C的转入操作好像没发生过一样,成了一笔坏账。

这个问题的原因是原子性不能保证可见性,当前事务看不到其它事务提交的结果,这才导致了数据的不一致。事实上可以使用排它锁来保证一致性。对账号A和账号B这两个资源进行加锁,事务获得锁才能执行,执行完才释放锁。这样事务是串行化执行的,当前事务肯定是能看到前一个事务提交结果的,数据一定是强一致性的。

使用到锁就要考虑死锁问题了,死锁问题说的是两个进程在不同方向抢占相同的共享资源。我们可以通过碰撞检测来发现系统中是否存在死锁,每个进程都记录已拥有和等待中的锁,如果出现了回环,说明有死锁。解决死锁的一般办法是锁等待超时。

使用锁时除了死锁还要考虑性能问题,排它锁是简单粗暴的方法,但是性能有点不忍直视。这时就得考虑一些优化策略了,比如减少锁的覆盖范围、减少锁的持有时间、使用并行代替串行。

数据库的设计大师正是考虑到这些,才引入了事务隔离性。

第一种事务隔离性是序列化读写。所有的事务放入到队列中依次执行,比如读写-写读-读读-写写。

第二种是读已提交。当前事务只能读取到其他事务已提交的结果,这种隔离下读-读、读-写都是可以并行执行的,因为当前事务依赖的数据是前一个写操作的结果。

第三种是可重复读。在同一个事务中,多次读取到的结果是一致的。这种隔离下读-读、读-写都是可以并行执行的。

第四种是读未提交。当前事务能看到其他事务还没有提交的中间状态,这种隔离下,只有写锁,读是不加锁的,所以除了写-写,读-写、写-读、读-读都是可以并行的。代价是出现脏读。

透过这四种事务隔离,明显能看到读写锁带来的收益,那能不能再优化下呢?

答案是可以的,秘决就是多版本并发控制MVCC,它的本质是写时复制Copy on write。行记录每次修改时都会产生一个快照和一个版本号,版本号是单向增长的逻辑时间戳,用来表示先后顺序。而读操作只会读取到早于当前事务版本的记录。显然,这种技巧非常适合读多写少的场景,而且能达到读未提交的并发度,隔离级别更好。

既然读-写、写-读、读-读都是可以并行的,写-写也能并行就更好了。

我们先来看下写-写并行会有什么问题。假设用户A要给用户B转账100元,用户B也要给用户A转账100元,考虑到事务间原子操作顺序的不可见性,用户A的余额可能会在原来基础上增加了100元,银行得损失100元。针对这种情况,需要借助乐观锁的思想来保证数据的一致性,针对同一行记录,只有高版本的事务更新能成功,低版本的事务更新得回滚掉。缺点是并发高时失败率高,需要不断重试。

除了事务隔离,数据库设计的大师为了提高并发效率,还做了很多优化。比如每次写操作并不直接持久化到磁盘中,而是暂时存放在易丢失的内存中,然后通过一定的机制异步同步到磁盘。这样就保证了数据的持久性,确保事务一旦提交,操作肯定会固化到数据库中。类似生活中这种场景,餐馆老板娘很忙的时候,就把每笔交易写在黑板上,当老板娘空闲、黑板写满或者餐馆打烊后再整理写入到账本中。

谈谈数据库的事务ACID的更多相关文章

  1. 数据库零基础之---了解数据库的事务[ACID]

    事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功. 我们先举一个例子来描述一下事务: 假设要张三通过银行给李四进行转账1000元钱,张三原有余额10000元整,李四有人民币 ...

  2. 数据库事务ACID详解(转载)

    转载自:http://blog.csdn.net/shuaihj/article/details/14163713 谈谈数据库的ACID 一.事务 定义:所谓事务,它是一个操作序列,这些操作要么都执行 ...

  3. 【转】数据库事务ACID以及事务隔离

      本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指 ...

  4. 数据库中事务的四大特性(ACID)

    本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指事务 ...

  5. 【数据库】事务,ACID,CAP和一致性

    什么是事务 事务是指由一系列数据库操作组成的一个完整的逻辑过程,这个过程中的所有操作要么都成功,要么都不成功.比如:常见的例子就是银行转账的例子,一次转账操作会包含多个数据库操作,而这些数据库操作需要 ...

  6. 带你了解数据库中事务的ACID特性

    前言 前面我们介绍过数据库中 带你了解数据库中JOIN的用法 与 带你了解数据库中group by的用法的相关用法.本章节主要来介绍下数据库中一个非常重要的知识点事务,也是我们项目中或面试中经常会遇到 ...

  7. 谈谈数据库的ACID

    一.事务 定义:所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位. 准备工作:为了说明事务的ACID原理,我们使用银行账户及资金管理的案例进行分析. // 创建 ...

  8. spring 传播行为与数据库事务ACID

    数据库事务ACID特性 数据库事务正确执行的4个基础要素是原子性(Atomicity).一致性(Consistency).隔离性(Isolation)和持久性(Durability). •原子性:整个 ...

  9. 数据库事务ACID特性(原子性、一致性、隔离性、持久性)

    ACID特性: 原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持久性(Durability) 原子性:一个事务必须被视为一个不可分割的最小工作单元,整个 ...

随机推荐

  1. 那些jdk中坑你没商量的方法

    前言:jdk作为我们每天必备的调用类库,里面大量提供了基础类供我们使用.可以说离开jdk,我们的java代码寸步难行,jdk带给我们的便利可谓是不胜枚举,但同时这些方法在使用起来也存在一些坑,如果不注 ...

  2. linux字符串转数字

    方法一: [root@ffcs211 test_dir]# echo "96.56"| awk '{print int($0)}' 输出结果 96 方法二: A="2&q ...

  3. Android开发之解决Error:(16) Error: "ssdk_baidutieba_client_inavailable" is not translated in "en" (Englis

    由于添加ShareSDK文件,导致打包突然报错, 错误信息: Error:(16) Error: "baidutieba_client_inavailable" is not tr ...

  4. Vue.js学习(八)—— 树形结构下拉框组件vue-treeselect

    vue-treeselect是一个多选组件,具有对Vue.js的嵌套选项支持. 具有嵌套选项支持的单个和多个选择 模糊匹配 异步搜索 延迟加载(仅在需要时加载深层选项的数据) 键盘支持(使用Arrow ...

  5. Sqli-labs 1-10

    Less 1-4(基础注入) 基础知识: table_schema:数据库的名称 table_name:表的名称 column_name:列的名称 information_schema:表示所有信息, ...

  6. Python の 在 VSCode 中使用 IPython Kernel 的方法

    本文介绍,在 VSCode 使用 IPython Kernel,的设置方法. 要达到的效果: 只需按下 Ctrl+:,选中的几行代码,就会自动发送到 IPython Kernel,并运行,得到结果!当 ...

  7. [Python]在当前目录下创建三个目录

    import os os.mkdir("2018-03-16-b018") os.mkdir("2019-03-16-b019") os.mkdir(" ...

  8. 转载:MySQL万字总结篇

    转载自:https://database.51cto.com/art/202001/609409.htm 开局一张图 这张图是重点!!!咱要先对 MySQL 有一个宏观的了解,知道他的执行流程. 一条 ...

  9. 在Nginx里指定ip_hash的方式解决Tomcat集群session的问题

    据称,Tomcat集群session同步方案有以下几种方式: 1)使用tomcat自带的cluster方式,多个tomcat间自动实时复制session信息,配置起来很简单.但这个方案的效率比较低,在 ...

  10. [Java数据结构]Queue

    Queue扩展了Collection,它添加了支持根据先进先出FIFO原则对元素排序的方法. 当对Queue调用add和offer方法时,元素始终添加在Queue的末尾:要检索一个元素,就要使用一个元 ...