一篇文章把-InnoDB-的事务机制给你弄的明明白白,帮你深度探寻Spring循环依赖源码实现

小王:我肯定付款了啊,不然怎么下单。

老板说:我没收到钱啊。你把付款的截图发给我。

小王说:我吃饭还能不付钱吗,你等着。

于是小王给老板截图了,老板拿着截图去找了美团技术,美团技术一查,转账失败。跟老板说不好意思,今天这代码是实习生写的,我们马上开除他,稍后转给你。这时候老板一颗悬着的心才放下,可不能一天就卖一份水饺还没收到钱,这不亏大了呢!

以上纯属虚构,没有诋毁美团实习生的意思。

从上面的问题看,付款成功了,转账失败了,这时候用户吃到了饭,但是老板没收到钱。放在正常的堂食,你不先付款,估计人儿就的赶你出去,一手交钱一手交货买卖不变的道理。

我们引申出一个概念:最小操作单元。即我们人为定义了一个业务场景,这个场景中的操作要么全部成功,要么全部失败。

英语原文中把这种最小操作单元定义为:transaction ,在英语中的解释是:

an occasion when someone buys or sells something, or when money is exchanged or the activity of buying or selling something:

  • a business transaction
  • Each transaction at the foreign exchange counter seems to take forever
  • We need to monitor the transaction of smaller deals.

通俗的说就是我们做某事所发生的这个时机或这个场景,代指这整个的发生过程。在 MySQL 中我们把 transaction 翻译为 事务,个人感觉中文意思总和英文有点不搭。

上面这个例子中我们可以了解到 transaction 存在的主要意图:

  1. 在最小操作单元中保持稳定的操作,即使在故障时也能恢复到操作之前的状态保持数据一致性。
  2. 保持各个最小操作单元之前互相隔离,以防止互相交互产生的覆盖性错误。

一般需要事务来控制的场景发生在:

更新–插入–选择–插入–

即一个最小操作单元中保持两个及以上的非查询操作。

事务结束的两种可能方式:

  • commit:提交最小操作单元中的所有操作。
  • terminate:操作终止,最小操作单元中所有修改无效。

数据库操作的环境:

  • 共享-多用户并发访问
  • 不稳定-潜在的硬件/软件故障

事务所需环境:

  • 不共享 - 一个事务内的操作不受其他事务影响
  • 稳定 - 即使面对系统故障,当前事务的操作也能保留现场

一个事务一旦开始,则必须确保:

  • 所有操作必须可回溯
  • 所有操作对后续操作的影响必须是可见的

一个事务开始的过程中必须确保:

在该事务结束之前其他事务看不到它的结果。

如果事务中止:

必须确保当前事务所有可能影响数据一致性的操作都会被清理。

如果系统出现故障:

必须确保重新启动时所有未提交的事务都会被清理。

针对以上事务操作过程中可能会出现的问题,抽象出事务如果满足以下条件,则可以保证数据完整性:

  • Automicity(原子性)

要么事务中的所有任务都必须发生,要么都不发生。

  • Consistency(一致性)

每个事务都必须保留数据库的完整性约束(已声明的一致性规则)。它不能使数据处于矛盾状态。在执行期间,一系列数据库操作不会违反任何完整性约束。

  • Isolation(隔离性)

两个同时进行的事务不能互相干扰。交易中的中间结果必须对其他交易不可见。其他一系列数据库操作无法看到一系列数据库操作的中间状态。

  • Durability(持久性)

已完成的事务以后不能中止或放弃其结果。它们必须在崩溃后通过(例如)重新启动DBMS持续存在。保证已提交的一系列数据库操作将永久保留。

特意查证了一下,关于事务四大特性的提出最早是在 1983 年由 Andreas Reuter 和 Theo Haerder 两位关系型数据库研发的鼻祖在论文:Principles of transaction-oriented database recovery 中提出。论文链接,感兴趣的可以下载来看看。

事务的 ACID 特性概念简单,但不是很好理解,主要是因为这几个特性不是一种平级关系:

  • 只有满足一致性,事务的执行结果才是正确的。
  • 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。 在并发的情况下多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
  • 事务满足持久化是为了能应对数据库崩溃的情况。
InnoDB 如何实现事务

鉴于 MyISAM 引擎不支持事务,支持事务的引擎只有 InnoDB,所以下面关于事务的讲解都是基于 InnoDB引擎。

在 InnoDB引擎中实现事务最重要的东西就是日志文件,保证事务的四大特性主要依靠这两大日志:

  • redo log :保证事务持久性
  • undo log:回滚日志,保证事务原子性

两大日志系统分别保证了持久性和原子性,另外还有两大特性是通过什么来保证的呢?

一致性 和 隔离性 是通过 MVCC 机制 和 锁机制来一起控制。先提前介绍,后面我们详解讨论。

典型的事务操作会遵循如下流程:

start transaction;
… # do your business
commit;

start transaction 标识事务的开始,直到遇到 commit 才会提交事务。在该事务过程中如果出现问题,会自动调用 rollback 逻辑回滚该事物已完成的 sql。

非显式开启事务

MySQL 中默认采用的是自动提交的模式:

mysql > show variables like ‘autocommit’;
±-----------------±------+
| Variable_name | Value |
±-----------------±------+
| autocomment | ON |
±-----------------±------+

自动模式下,你无需显式的输入 start transaction 作为开头和使用 commit 作为结尾来标识一个事务。每个sql 语句都会被作为一个事务提交。

当然你也可以关闭自动提交事务机制:

mysql > set autocommit = 0;

需要注意的是:autocommit 参数的修改指只针对当前连接,在一个连接中修改该属性并不会影响别的连接。

不被 autocommit 影响的操作

MySQL 中提供了一些不会被 autocommit 属性值所影响的特殊指令,这些指定即使在事务中执行,他们也会立刻执行而不是等到 commit 语句之后再提交,这些特殊指令包括:DDL(create table / drop table / alter table)lock tables等等。

我们探讨事务到底在探讨什么?

事务的定义我们已经了解,无非就是把几个有上下文关联的 sql 放在一起操作要么全部成功,要么全部失败。道理很简单,那我们分析这么多到底在分析什么呢?貌似难的点不在于打包执行,在于如果让这些打包命中不互相影响&

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值