NOTE

数据库事务

1. 什么是事务 将多个读写操作合并成一个逻辑单元,视作一个操作执行 这个操作满足ACID特性 2. 为什么需要事务 主要是为了让应用层简化对一系列问题的处理 事务是一个抽象层,应用程序 事务 数据库。 通过事务的抽象应用程序可以假装数据库不会崩溃(原子性),没有其他人同时访问数据库(隔离),存储设备是完全可靠的(持久性) 所有这些错误都被简化为 事务中止 ,而应用需要的仅仅是重试 3. 事务的特性 3.1. A (原子性) 3.1.1. 原子性是什么 无论有多少条sql语句,要么整体执行失败,要么整体执行成功。 原子性 这个的原子性不是指并发的,即不是描述多个线程同时访问相同的数据会发生什么

Database创建于 更新于 约 4 分钟读完historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 什么是事务

  • 将多个读写操作合并成一个逻辑单元,视作一个操作执行
  • 这个操作满足ACID特性

2. 为什么需要事务

  • 主要是为了让应用层简化对一系列问题的处理
  • 事务是一个抽象层,应用程序->事务->数据库。
    • 通过事务的抽象应用程序可以假装数据库不会崩溃(原子性),没有其他人同时访问数据库(隔离),存储设备是完全可靠的(持久性)
    • 所有这些错误都被简化为事务中止,而应用需要的仅仅是重试

3. 事务的特性

3.1. A (原子性)

3.1.1. 原子性是什么

  • 无论有多少条sql语句,要么整体执行失败,要么整体执行成功。
  • 原子性
    • 这个的原子性不是指并发的,即不是描述多个线程同时访问相同的数据会发生什么。并发是由隔离性描述的
    • 用可终止性描述更为准确:一组操作如果中间发生了错误,那么可以终止这个事务,并且丢弃该事务进行的所有写入

3.1.2. 原子性是如何实现的

InnoDB事务.md

3.2. C(一致性)

3.2.1. 一致性是什么

  • 系统从一个正确的状态,迁移到另一个正确的状态
    • 当前的状态满足预定的约束就叫做正确的状态
  • 一致性是最基本的属性,其它的三个属性都为了保证一致性而存在的。

3.2.2. 一致性是如何实现的

  • 原子性,隔离性和持久性是数据库的属性,而一致性准确来说是应用程序的属性。应用程序可以通过数据库的原子性和隔离属性来实现一部分一致性,但更多的需要应用程序自己考虑。因此,一致性实现分为两个方面:
    • 数据库本身:单个事务的一致性由原子性保证,并发事务的一致性需由隔离性保证。
    • 应用层面:程序员自己保证

3.3. I(隔离性)

3.3.1. 隔离性是什么

  • 多个事务同时访问相同的数据,可能会有并发问题。隔离性就是用来解决并发问题的
  • 两个事务隔离意味着同时执行的事务之间不会相互干扰,也即事务A看不到事务B运行时的中间结果

3.3.2. 并发问题

3.3.2.1. 脏写

  • 事务A修改了事务B修改过但未提交的数据

  • 场景

    • 如果有一个val是10,事务B先对其修改为10,事务A后对其修改为20,最后结果应该是20,但是实际上事务A的写被事务B的写覆盖了
    事务A 事务B
    写val为10(未提交)
    写val为20(已提交)
    写提交
    读val为10
3.3.2.1.1. 如何解决脏写问题
  • 行锁

3.3.2.2. 丢失更新

  • 两个事务从数据库中读取一些值,修改它并写回数据库,即读取-修改-写入序列,这个操作不是一次性完成的

  • 场景

    • 如果有一个val是10,事务A和事务B都要对其+10,那么最终的结果应该是30,但是实际上事务B重写了事务A的val
    事务A 事务B
    读val为10
    读val为10
    写val+10为20(已提交)
    写val+10为20(已提交)
3.3.2.2.1. 如何解决丢失更新问题

3.3.2.3. 脏读

  • 事务A读取了事务B修改过没有提交的数据

  • 场景

    • 如果有一个val是10,事务B对其+10但没有提交,事务A两次读取应该是一样的,但是实际上事务A读到的结果不一样
    事务A 事务B
    读val为10
    写val+10为20(未提交)
    读val为20
3.3.2.3.1. 如何解决脏读问题
  • 可以使用行锁,但是效率太差
  • MVCC

3.3.2.4. 不可重复读

  • 事务A两次查询,条件相同,但是结果不同。由于事务B提交后修改这条数据。

  • 场景

    • 如果有一个val是10,事务B对其+10并提交,事务A两次读取应该是一样的,但是 实际上事务A读到的结果不一样
    事务A 事务B
    读val为10
    写val+10为20(更新+已提交)
    读val为20
3.3.2.4.1. 如何解决不可重复读问题
  • MVCC

3.3.2.5. 幻读

  • 事务A两次查询,条件相同,数量不一致。由于事务B提交后新增了记录。

  • 场景:

    • 如果有一张表记录数为10,事务A插入一条新纪录,事务B两次读取记录数应该是10,但是实际上事务B读到的记录数不一样
    事务A 事务B
    读记录数为10
    写入一条新纪录(新增或者删除+已提交)
    读记录数为11
3.3.2.5.1. 如何解决幻读问题
  • 串行访问
  • 两阶段锁
    • 谓词锁:不好实现
    • 索引范围锁:MySQL用的就是这个,叫做Gap Locks
  • 序列化快照隔离

3.3.3. 隔离级别

不同的隔离级别能解决不同的并发问题,每个具体的数据库隔离级别解决的问题不一样,但是一般来说,脏写问题太严重,每个数据库的任何隔离级别都不允许出现

3.3.4. D(持久性)

3.3.4.1. 持久性是什么

  • 事务一旦提交,即使系统发生了崩溃,这个事务对数据库所作的更改也不能丢失

3.3.4.2. 持久性是如何实现的

3.4. 参考

讨论

使用 GitHub 账号参与讨论,评论会保存在 GitHub Issues 中。在 GitHub 查看