DDIA(数据密集型应用系统设计) 读书笔记-第七章

295 阅读4分钟

image.png

事务

个人理解,事务最简单的定义就是所有的读写都是一个执行整体,要么成功,要么失败。如果失败,可以安全重试。不用考虑并发一致性等,就只关注操作本身。当然提到事务,最完整的定义,作为基础的ACID是绕不开的。

  • 原子性

    保证当前操作作为整体,不关心多个操作是否并发影响。比如批量操作中间出问题,成功部分将会被丢弃。

  • 一致性

    个人理解这个一致性和CAP理论的C是有关联的。CAP理论的C说的是数据的一致性,ACID的C范围更大,不仅有数据的一致性,还有操作的一致性,比如读操作可以立即读到提交的更新操作。此外还有一些约束的一致性。总结的说包含了两个层面,一个是数据库机制层面保证的一致性,另一个层面是业务上的一致性,应用要保证数据的一致性

  • 隔离性

    指的是数据相关的隔离。在事务并发场景下不会出现数据混乱的情况

  • 持久性

    事务成功结束后,对数据修改落盘,是永久性的。

除了一致性外,原子性,一致性,持久性,只要违反一个,那么事务就是失败,数据都会回滚。

隔离

ACID中最关键的特性是隔离,事务隔离性针对并发事务而言的。在现实业务场景中,大部分对数据库的操作都是并发的。隔离也是分几个级别,读未提交这个隔离最弱,基本上和没做隔离一样,就不提了。另外书中有些翻译和常提的名词不太一样,我会按我理解来总结

  • 读已提交

    写操作方面,是可以防止脏写的。脏写就是两个事务同时操作一个数据,在自己的事务内部互相修改,互相影响。实现方式,通常是采用行级锁,事务修改数据库时,先去拿锁,事务提交或者回滚释放锁。

    读操作方面,是可以防止脏读的,脏读就是事务在执行过程中,能看到另一个事务还没有提交的数据。实现方式,一种是利用读锁,但是读锁遇到时间较长的写入,等待时间比较长影响效率,一般都不会采用。另一种是维护旧值和和写入事务将要设置新值的两个版本,其实也就是MVCC

    这种级别是不能解决不可重复读和幻读问题。

    不可重复读和幻读,个人理解相同点都是同一个事务多次读取不一致。但幻读强调的是集合增减,比如第一次读取的时候数量1,在这期间另一个事务插入了一条,第二次读取的时候梳理变成2.而不可重复读指的是单条数据自身的修改。

  • 可重复读

    这个是mysql默认设置的隔离级别。利用了MVCC快照实现数据的隔离,当发起事务的时候,会取当前已提交事务的数据,忽略掉正在进行中事务以及回退的事务,此外所有的写入是对事务中查询动作可见的,这个也是造成幻读在可重复读层面没法解决的原因

    索引这块儿理解的不够好,按照原文的说法,一种是继续维护原来内存页中的索引,但索引会指向多个版本的数据,事务开始后,过滤当前事务看不到的版本;另一种是创建新的b树,在没有提交事务前,不会与原来的数据页发送关联,但提交后,需要进行数据的维护和回收。

  • 串行化

    这个是最强的隔离级别,在现实场景中用到的比较少,靠牺牲性能来保证。串行化实现方式包括了三种,一种是严格按照串行顺序执行,这个其实主要是靠业务层面或者中间件保证,对数据库完全串行化操作;一种是通过锁方式,书中起得名字叫两阶段加锁(和2PC不一样),两个阶段分别是获取锁和释放锁;最后一种是乐观并发控制,也就是我们说的乐观锁,那前一种其实也是悲观锁。

    如果项目场景需要考虑串行化的话,那最好保证短事务且高效,写操作的数据量最好足够低,读操作尽量去缓存,同时不要搞分布式事务。