• DDIA


    第7章, 事务.

    概览

    • 事务是提供一种保证, 要么所有写入操作都成功, 要么都失败
    • ACID的概念解读.
    • 隔离级别: 读未提交(Read Uncommitted), 读已提交(Read Committed), 快照隔离(snapshot isolation), 可重复读(repeatable read), 可序列化(Serializable)

    事务的概念

    事务提供一种保证, 事务中的所有读写操作视为单个操作来执行, 要么成功(commit), 要么失败(abort, rollback), 如果失败, 应用程序可以安全的重试.

    ACID

    ACID代表原子性(Atomicity), 一致性(Consistency), 隔离性(Isolation), 持久性(Durability).

    更为宽松的一致性要求, BASE, 代表基本可用性(Basically Avaliable), 软状态(Soft State), 最终一致性(Eventual consistency).

    原子性(Atomicity)定义: 能够再错误时中止事务, 丢弃该事务的所有写入的能力. 不能只写一半, 要么都成功, 要么都失败.

    一致性(Consistency)定义: 本文作者认为, 一致性是应该由应用程序来保证, 而不是数据库, 所以数据库没有一致性.

    隔离性(Isolation)定义: 同时执行的事务是相互隔离的, 不能相互冒犯.

    持久性(Durability)定义: 持久性是一个承诺, 一旦事务成功完成, 即使数据库崩溃, 数据就不会丢失. 意味着写入硬盘或SSD.

    隔离级别

    除了可序列化(Serializable), 其他隔离级别都定义为弱隔离级别.

    读未提交(Read Uncommitted)

    一个事务可以看到另外一个事务没有提交的数据, 一般称为脏读.

    读已提交(Read Committed)

    提供了2个保证:

    1. 从数据库读时, 只能看到已提交的数据, 没有脏读(dirty reads).
    2. 写入数据库时, 只会覆盖已经写入的数据, 没有脏写(dirty writes).

    防止脏读, 用户2只有在用户1的事务提交后才能看到x的新值

    最常见的情况是, 数据库通过使用行锁(row-level lock)来防止脏写

    快照隔离(snapshot isolation)和可重复读(repeatable read)

    快照隔离提供一种保证, 一个事务中, 只能看到事务开始前某个时间点的旧数据, 不能看到事务处理期间其他事务修改的值.

    下图演示了不可重复度(nonrepeatable read)的情况, Alice的2次读取行为发生在一个事务中, 其中第2次读取到了其他事务修改的新值.

    快照隔离(snapshot isolation): 每个事务都从数据库的一致快照(consistent snapshot) 中读取——也就是说,事务可以看到事务开始时在数据库中提交的所有数据。即使这些数据随后被另一个事务更改,每个事务也只能看到该特定时间点的旧数据.

    快照隔离对长时间运行的只读查询(如备份和分析)非常有用.

    快照隔离的实现: 使用了多版本并发控制(MVCC, multi-version concurentcy control), 首先通过写锁防止脏写, 然后添加created_bydeleted_by来分别表示这些数据被哪些事务创建和删除, 每个事务都会被分配一个事务ID, 事务ID是自增的. 通过以下规则判断是当前事务可以看到的数据:

    1. 在每次事务开始时,数据库列出当时所有其他(尚未提交或尚未中止)的事务清单,即使之后提交了,这些事务已执行的任何写入也都会被忽略。
    2. 被中止事务所执行的任何写入都将被忽略。
    3. 由具有较晚事务ID(即,在当前事务开始之后开始的)的事务所做的任何写入都被忽略,而不管这些事务是否已经提交。
    4. 所有其他写入,对应用都是可见的。

    可序列化(Serializable)

    提供了保证, 事务并行执行好像挨个执行一样, 是最强的隔离级别.

    常用三种技术来实现可序列化:

    1. 真的串行执行
    2. 两相锁定(2PL, two-phase locking), 几十年来唯一的选择
    3. 乐观并发控制技术, 例如可序列化的快照隔离(serializable snapshot isolation)

    1. 真的串行执行

    以往认为, 为了提高效率必须要采用多线程, 但是现在人们发现, 有时候使用单线程反而性能更高. 例如Redis, 参考博文 https://www.cnblogs.com/myseries/p/11733861.html.
    其中2个进展是人们产生了反思

    1. RAM足够便宜了,许多场景现在都可以将完整的活跃数据集保存在内存中。当事务需要访问的所有数据都在内存中时,事务处理的执行速度要比等待数据从磁盘加载时快得多
    2. 数据库设计人员意识到OLTP事务通常很短,而且只进行少量的读写操作. 相比之下,长时间运行的分析查询通常是只读的,因此它们可以在串行执行循环之外的一致快照(使用快照隔离)上运行。

    在存储过程中封装事务
    如果执行一个事务, 有多条sql语句, 那么需要与数据库进行多次的来回交互, 事务会很慢. 我们把这些逻辑封装到存储过程中, 调用存储过程, 这样所有的操作都在数据库的内存中完成, 减少了与客户端的交互, 事务会变快.

    传统的数据库的存储过程有几个缺点:

    1. 存储过程使用的语言不够方便, 如SQL Server使用T-SQL, 远没有使用C#来写的方便.
    2. 调试困难
    3. 写的不好的存储过程可能会占用大量内存或者CPU, 限制数据库的性能

    但是现代的存储过程实现放弃了PL/SQL,而是使用现有的通用编程语言:VoltDB使用Java或Groovy,Datomic使用Java或Clojure,而Redis使用Lua.

    在特定条件下, 真的可以串行执行事务. 条件如下:

    • 每个事务都必须小而快,只要有一个缓慢的事务,就会拖慢所有事务处理。
    • 仅限于活跃数据集可以放入内存的情况。很少访问的数据可能会被移动到磁盘,但如果需要在单线程执行的事务中访问,系统就会变得非常慢。
    • 写入吞吐量必须低到能在单个CPU核上处理,如若不然,事务需要能划分至单个分区,且不需要跨分区协调。

    2. 两相锁定(2PL)

    只要没有写入, 就允许多个事务同时读取一个对象, 但对象只要有写入(修改或删除), 就需要独占访问权限:

    • 如果事务A读取了一个对象, 事务B想写入该对象, B必须要等待A提交或中止才能继续.
    • 如果事务A写入了一个对象, 事务B想读取该对象, B必须要等待A提交或中止才能继续.

    2PL用于MySQL(InnoDB)和SQL Server中的可序列化隔离级别,以及DB2中的可重复读隔离级别.

    有2个锁, 共享锁(shared)和排它锁(exclusive).

    • 若事务要读取对象,则须先获得共享锁。允许多个事务同时持有共享锁。但如果另一个事务已经在对象上持有排它锁,则这些事务必须等待。
    • 若事务要写入一个对象,它须先获取排它锁。没有其他事务可以同时持有排它锁, 所以如果对象上存在任何锁,该事务必须等待

    由于使用了这么多的锁,因此很可能会发生:事务A等待事务B释放它的锁,反之亦然。这种情况叫做死锁(Deadlock)。数据库会自动检测事务之间的死锁,并中止其中一个,以便另一个继续执行。被中止的事务需要由应用程序重试。

    3. 序列号快照隔离(SSI, serializable snapshot isolation)

    两阶段锁是一种所谓的悲观并发控制机制(pessimistic) :它是基于这样的原则:如果有事情可能出错(如另一个事务所持有的锁所表示的),最好等到情况安全后再做任何事情。这就像互斥,用于保护多线程编程中的数据结构。

    SSI是一个相当新的算法,避免了先前方法的大部分缺点。它使用乐观的方法,允许事务执行而无需阻塞。当一个事务想要提交时,它会进行检查,如果执行不可序列化,事务就会被中止。

    这里有点难懂, 我选择略过。。。

  • 相关阅读:
    vs 2005 下 逐阶 海量测试堆算法 记录 【永久更新】
    预备 归并排序 –from wikipedia 演示
    有关堆栈溢出(in vs 2005)的读书笔记堆栈中 申请大数组
    Heapsort 代码 学习笔记 阳春三月版
    那些基础算法的 数学不等式 @快排分划 @kmp覆盖函数
    珠儿 快排 三月版本(主题:学代码,撘框架)(永久更新)
    c 语言格式输出 浮点数 不要用 整形输出 教训
    修改 堆栈大小 普适性方案总结 (跨平台 windows linux 栈设置大小)
    转tip 在VC下编译使用unistd.h,times.h等文件
    DB2用命令窗口连接数据库
  • 原文地址:https://www.cnblogs.com/winwink/p/DDIA6-Transaction.html
Copyright © 2020-2023  润新知