设为首页 加入收藏

TOP

事务与隔离级别------《Designing Data-Intensive Applications》读书笔记10(二)
2019-09-17 18:55:05 】 浏览:43
Tags:事务 隔离 级别 ------ Designing Data-Intensive Applications 读书 笔记
地改变事务A正在读取的数据。
  • 事务A获取了数据的写锁,事务B想读取对应的数据,事务B也必须等到事务A提交或中止后方可进行读取。
  • 事务A获取了数据的写锁,事务B想写对应的数据,事务B也必须等到事务A提交或中止后方可进行写入操作。
  • 由上面三个规则可以看出,2PL提供串行化的访问,它可以防止任何的并发问题,但是由此带来的问题也显而易见,数据库的并发能力大大降低了。

    共享锁与独占锁

    两阶段锁的逻辑是通过共享锁与独占锁共同来实现的:
    如果事务A要读取数据,则必须先获取共享锁。数据库允许多个事务同时拥有共享锁,但如果另一个事务拥有独占锁,则其他事务要获取共享锁则必须等待。

    如果事务A要写入数据,则必须先获取独占锁。任何其他事务都不能同时拥有锁,(无论是共享还是独占)因此如果对象上存在任何锁,事务A必须等待。

    如果事务A先读取数据,然后写入数据。它可以将共享锁升级为独占锁。升级与直接获得独占锁相同。

    在事务获得锁之后,它必须继续持有锁直到事务结束(提交或中止)。这就是“两阶段”的名称:第一阶段在获取锁时,第二阶段释放锁。

    由于使用了这么多锁,所以很容易发生事务A被卡住等待事务B释放它的锁,反之亦然。这种情况称为死锁。数据库自动检测死锁之后会终止事务,然后重启事务排队。

    序列化的快照隔离(SSI)

    两阶段锁(2PL)由于采取了悲观的并发控制,不但容易引起死锁,且性能低下。所以接下来我们要来看看序列化的快照隔离(SSI),它提供了完整的串行化,但是只有很小的性能损失相比两阶段锁。

    当我们以前讨论快照隔离中的并发写问题,是因为事务从数据库读取一些数据,检查读取结果,并决定根据它看到的结果采取一些操作。然而,在快照隔离的情况下,原始查询的结果在事务提交时可能不再是最新的,因为数据可能在此期间进行了修改。所以查询和事务中的写之间可能存在因果依赖关系。为了提供串行化隔离,数据库可以检测到这种情况,并且终止不合法的事务。

    检测是否读取旧的数据

    快照隔离通常采用多版本并发控制实现,当一个事务读取一个数据库的一致性快照,它忽略了新的写入。为了防止这种异常,数据库需要跟踪事务时读取时是否忽略了另一个事务的写操作,当事务要提交时,数据库检查任何已忽略的写操作。如果忽略了写操作,则必须中止事务。

    为什么要等到提交时,而不是检测到读取旧数据时就立即终止事务呢?那么,如果事务如果是只读事务,则不需要中止,在事务进行读取时,数据库还不知道该事务是否稍后将执行写入操作。上文Alice与Bob请假的例子可以通过这样的方式避免并发写的问题:
    检测到读取了旧的数据,事务终止

    检测影响先前读取的写入

    如果并没有检测到读取了旧的数据,仍然有可能出现并发写入的问题。

    所以当事务写入数据库时,它记录读取受影响数据的任何其他事务的索引。一旦第一个事务是成功提交,其他所有相关的索引事务必须终止。通过这样快照隔离的方式,保证了并发写入的安全性。同样是上文的例子,下图暂时了索引终止技术:

    通过事务索引终止了被影响数据的其他事务

    许多工程细节影响算法在实践中的工作效果。跟踪事务的读写的粒度。如果数据库非常详细地跟踪每一个事务的活动,那么它就可以精确地判断哪些事务需要中止,但是这些开销会变得很大。而不太详细的跟踪事务会更快速,但可能导致更多的事务被中止。相比与两阶段锁,可串行化隔离快照是大有好处的:一个事务不需要阻塞等待另一个事务持有的锁。

    小结:

    我们在本篇之中总结了数据库事务与隔离运用到的多种策略与技术,希望大家能够更好的认识事务在数据库系统之中的重要意义,并且能够为自己的开发环境运用最恰当的隔离级别。

    首页 上一页 1 2 下一页 尾页 2/2/2
    】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
    上一篇分布式系统的烦恼------《Designi.. 下一篇java抽象类,接口与异常

    最新文章

    热门文章

    Hot 文章

    Python

    C 语言

    C++基础

    大数据基础

    linux编程基础

    C/C++面试题目