周志明的软件架构课
周志明
博士,远光软件研究院院长,《深入理解 Java 虚拟机》《凤凰架构》等书作者
54203 人已学习
免费领取
课程目录
已完结/共 74 讲
架构师的视角 (24讲)
周志明的软件架构课
15
15
1.0x
00:00/00:00
登录|注册

11 | 本地事务如何实现原子性和持久性?

你好,我是周志明。
在接下来的五节课里,我们将会一起讨论软件开发中另一个常见的话题:事务处理。
事务处理几乎是每一个信息系统中都会涉及到的问题,它存在的意义就是保证系统中的数据是正确的,不同数据间不会产生矛盾,也就是保证数据状态的一致性(Consistency)。
关于一致性,我这里先做个说明。“一致性”在数据科学中有严肃定义,并且有多种细分类型的概念。这里我们重点关注的是数据库状态的一致性,它跟课程后面第三个模块“分布式的基石”当中,即将要讨论的分布式共识算法时所说的一致性,是不一样的,具体的差别我们会在第三个模块中探讨。
说回数据库状态的一致性,理论上,要达成这个目标需要三方面的共同努力:
原子性(Atomic):在同一项业务处理过程中,事务保证了多个对数据的修改,要么同时成功,要么一起被撤销。
隔离性(Isolation):在不同的业务处理过程中,事务保证了各自业务正在读、写的数据互相独立,不会彼此影响。
持久性(Durability):事务应当保证所有被成功提交的数据修改都能够正确地被持久化,不丢失数据。
以上就是事务的“ACID”的概念提法。我自己对这种已经形成习惯的“ACID”的提法是不太认同的,因为这四种特性并不正交,A、I、D 是手段,C 是目的,完全是为了拼凑个单词缩写才弄到一块去,误导的弊端已经超过了易于传播的好处。所以明确了这一点,也就明确了我们今天的讨论,就是要聚焦在事务处理的 A、I、D 上。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了事务处理中的本地事务实现原理,重点关注了事务的原子性和持久性。作者首先解释了事务处理的意义,即保证数据的一致性,然后详细介绍了事务的ACID概念,即原子性、隔离性和持久性。在介绍事务场景和事例后,作者重点讲解了本地事务的概念和特点,指出本地事务是基于单一事务资源的、不需要全局事务管理器进行协调的事务处理方案。文章还提到了ARIES理论,指出现代主流关系型数据库在事务实现上深受该理论的影响。此外,文章还介绍了实现原子性和持久性所面临的困难,以及Commit Logging和Write-Ahead Logging的日志改进方案。总的来说,本文内容涉及数据库事务的实现原理和技术细节,对于想要深入了解事务处理的读者具有很高的参考价值。 文章深入探讨了事务处理中的本地事务实现原理,重点关注了事务的原子性和持久性。通过介绍ACID概念和本地事务特点,以及ARIES理论和日志改进方案,为读者提供了深入了解事务处理的技术细节和实现原理的参考价值。

该试读文章来自《周志明的软件架构课》,如需阅读全部文章,
请先领取课程
免费领取
登录 后留言

全部留言(45)

  • 最新
  • 精选
  • zhanyd
    FORCE策略,要求事务提交后,变动的数据马上写入磁盘,没有日志保护,但是这样不能保证事务的原子性,比如用户的账号扣了钱,写入了数据库,这时候系统崩溃了,商品库存的变更信息和商家账号的变更信息,都还没来得及写入数据库,这样数据就不一致了。 为了实现原子性,保证能够崩溃恢复,所以绝大多数数据库都采用NO-FORCE策略,为了实现NO-FORCE策略,就需要引入Redo Log(重做日志)来实现,即使修改数据时系统崩溃了,重启后根据Redo Log,可以选择恢复现场,继续修改数据,或者直接回滚整个事务。 换句话说就是,我先把我要改的东西记录在日志里,我再根据日志统一写到磁盘中,万一我在写入磁盘的过程中晕倒了,等我醒来的时候,我照着日志重新做一遍,也能成功。 Commit Logging方式实行了NO-FORCE策略,照理说这样已经实现了事务的功能,已经很牛逼了,但是当一个事务中数据量特别大的时候,等全部变更写入Redo Log然后再统一写入磁盘,这样性能就不是很好,就会很慢,老板就会不开心。 那能不能在事务提交之前,偷偷地先写一点数据到磁盘呢(偷跑)? 答案是可以的,这就是STEAL策略,但是问题来了,你偷摸地写了数据,万一事务要回滚,或者系统崩溃了,这些提前写入的数据就变成了脏数据,必须想办法把它恢复才行。 这就需要引入Undo Log(回滚日志),在偷摸写入数据之前,必须先在Undo Log中记录都写入了什么数据,改了什么地方,到时候事务回滚了,就按照Undo Log日志,一条条恢复到原来的样子,就像没有改过一样。 这种能够偷摸先写数据的方式就叫做Write-Ahead Logging,性能提高了,不过同时也更复杂了。 虽然复杂点,但是效果很好啊,mysql、sqlite、postgresql、sql server等数据库都实现了WAL机制呢。

    作者回复: 给你点赞

    2020-12-11
    15
    219
  • 蓝蓝
    感觉东西讲的比较清楚了,但是我看完一遍就觉得累了,感觉过会就会忘记,是我的脑容量不够吗?能请教下怎么办吗?

    作者回复: 不是。这与脑容量高低、是否聪明没有太多关系。 不妨稍微解一下“认知负荷”这个概念,在长时记忆中存储的信息越多,新知识中陌生的信息越少,就越能够降低接受新知识的负担。 我在开篇中提出写这部文档的目的是“系统性地整理自己的知识,将它们都融入既有的知识框架之中”,这并不是客气话,对我自己来说就是一种将知识以图式的形式存储于长时记忆中的方法,希望你也能找到适合自己的方法。

    2020-12-21
    5
    69
  • lmdcx
    我不知道多少人之前是被误导的, 反正我就是那个被误导的之一 或者说被困扰的之一. 我一直以为这4个都是目的, 现在才知道其中3个应该视为手段. 而且现在才清楚的知道 undo log 是为了STEAL force -> 每次提交数据是否必须落盘 STEAL -> 未提交数据是否可以落盘 这个细节我理解的对吗? 能让我天天做 CURD 的都听的懂事务的原理甚至其中的一些细节,老师真厉害!

    作者回复: force -> 每次提交数据是否必须【马上】落盘 STEAL -> 未提交数据是否可以【提前】落盘 你的理解对的。再补充括号中两个字的话会更准确。

    2020-12-11
    2
    38
  • 业余爱好者
    我也一直对acid这种提法感到困惑,不太明白为什么是这四个特性而非其他。 即使把c排除在外,aid这三种手段是正交的吗? 真不知道这种理论是怎么被发明出来的。是不是只要满足aid,就一定可以实现c?

    作者回复: 原子性,隔离性和持久性是正交的。 关于“是不是只要满足aid,就一定可以实现c”,C是应用程序视角看到的,如果你刻意地向数据库写入不一致的数据,数据库并没有什么办法阻止你制造出不一致的数据。这里我引用DDIA作者的一段话供你参考: Atomicity, isolation, and durability are properties of the database, whereas consis‐ tency (in the ACID sense) is a property of the application. The application may rely on the database’s atomicity and isolation properties in order to achieve consistency, but it’s not up to the database alone. 原子性,隔离性和持久性是数据库的属性,而一致性(在ACID意义上)是应用程序的属性。应用可能依赖数据库的原子性和隔离属性来实现一致性,但这并不仅取决于数据库。 “真不知道这种理论是怎么被发明出来的” 在这篇论文提出来的: Theo Härder and Andreas Reuter: “Principles of Transaction-Oriented Database Recovery,” ACM Computing Surveys, volume 15, number 4, pages 287–317, Decem‐ ber 1983. doi:10.1145/289.291

    2020-12-14
    2
    32
  • 青鸟飞鱼
    老师你好,对于mysql的先写日志和redis的后写日志,这两种有什么区别吗?时不时都听到redis不能保证数据持久性?

    作者回复: MySQL(及其他基于日志的DMBS)写日志的目的,与Redis中AOF日志并不相同。虽然两者都是为了崩溃恢复服务的,但MySQL必须保证崩溃恢复的原子性与持久性,那就必须保证每一个操作(事务)的成功完成,必须是以在日志中写入了该操作的完整的信息为标志。而Redis中的AOF日志是为了服务崩溃之后,尽可能重演历史来恢复现场,但并不强求绝对精确地恢复每一个已经进行的修改操作,即并不会保证持久性。这是因为哪怕将AOF设置为always,也不能保证绝对不出现写完数据之后,写日志之前不会出现崩溃。但也正因为操作是优先于日志来完成的,才让Redis有更高的性能上限。

    2020-12-19
    2
    21
  • 书生
    DDIA的作者也说ACID中的C是赠的,C真的是太可怜了。。。 另外,全篇文章都是干货啊,感觉老师应该有很多想说的都没说吧,不如写本书,不用太在意内容逻辑,想说点啥就写点啥,写个几百页(跟编译原理差不多就行),做个《程序员的枕边书》系列如何,哈哈

    作者回复: 是有写一本书,电子版是免费的:https://icyfenix.cn,纸质版大概在明年二月份会出来。 跟《编译原理》差不多就行……您太看得起我了,当年龙书我是跪着看的= =#

    2020-12-12
    4
    11
  • Jxin
    1.学习了。讲得真好。 课后题: 1.这个我不懂,猜下。因为Logging的方式比较稳定。无论你操作的数据量多大,能否保证一致性的时间开销都是记录操作日志这个动作的开销。Shadow Paging的话,会受操作数据的量级影响,不稳定,且并发度低。

    作者回复: 在这节讲的原子性与持久性上,Shadow Paging并没有什么问题。它的不足主要出现在下一节介绍的隔离性与并发能力上面。 最关键的不足是一个Page只上的数据同一时间只能被一个事务所修改,否则如果允许多个事务同时修改Page上的数据,其中一个提交另一个不提交就没法往下做了,如此高的串行度决定了整体并发能力必定低下。

    2020-12-11
    2
    9
  • stevensafin
    AID是正交的,这个该如何理解,希望老师指教

    作者回复: 就是字面意思。Orthogonality,是指不能相互替代,无法互相推导出来。

    2021-04-13
    2
  • Demon.Lee
    借着这里问老师一个数据库范式的问题, 最近发现一个项目,小伙伴们喜欢用外键,但我个人很少用外键了(反范式)。因为我的理解是,外键约束之类的校验应该放到业务层来做。同样,一些表增加冗余字段来提高查询效率(比如,评论表中除了有用户id,还有用户昵称),如果冗余字段更新(比如用户改了昵称),也需要通过业务服务来更新,而不是写触发器或存储过程来做。在数据库层做这些事情,一方面给数据库带来压力,二是业务开发人员可能都不知道这些逻辑(主要负责代码开发,不涉及数据库维护),(当然,一个人维护的小项目或数据量很小,这么做也没啥问题)。想听听老师平时项目中,类似的问题是如何做的,谢谢。 另外,弱弱的问一句,咱们这个课的纸质版出来了么(https://icyfenix.cn),之前看到评论说预计今年二月份出来。

    作者回复: 我在生产库上一律不建立外键(在开发库上可以商量)。 所有数据更新都应该在服务层去做,不采用触发器、存储过程。存储过程将明显提升会后分布式服务划分、采用分布式数据库(如tidb)的困难度,也降低程序的可测试性。 纸质书应该在5月底至6月初能够出来。

    2021-04-16
    3
    1
  • topsion
    老师的这门课简直是将自己凌乱的知识图谱规整起来的一门绝佳课程。麻烦问下纸质版的什么时候出版,I need it!

    作者回复: 争取618能预售吧:https://icyfenix.cn/introduction/about-book.html

    2021-05-30
收起评论
显示
设置
留言
45
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部