MySQL事务篇:ACID原则、事务隔离级别及事务机制原理剖析

引言

众所周知,MySQL数据库的核心功能就是存储数据,通常是整个业务系统中最重要的一层,可谓是整个系统的“大本营”,因此只要MySQL存在些许隐患问题,对于整个系统而言都是致命的。那此刻不妨思考一个问题:

MySQL在接受外部数据写入时,有没有可能会发生问题呢?

有人也许会笑着回答:“那怎么可能啊,MySQL在写入数据时怎么会存在问题呢”。

的确,MySQL本身在写入数据时并不会有问题,就算部署MySQL的机器断电/宕机,其内部也有一套健全的机制确保数据不丢失。但往往风险并不来自于表象,虽然MySQL写入数据没问题,但结合业务来看就会有一个很大的隐患,此话怎讲呐?先看案例:

-- 从库存表中扣减商品数量
UPDATE `zz_inventory` SET ......;

-- 向订单表、订单详情表中插入订单记录
INSERT INTO `zz_order` VALUES(....);
INSERT INTO `zz_order_info` VALUES(....);

-- 向物流表中插入相应的物流信息
INSERT INTO `zz_logistics` VALUES(....);

上述的伪SQL中,描述的是一个经典下单业务,先扣库存数量、再增加订单记录、再插入物流信息,按照正常的逻辑来看,上面的SQL也没有问题。但是请仔细想想!实际的项目中,这三组SQL是会由客户端(Java线程)一条条发过来的,假设执行到「增加订单记录」时,Java程序那边抛出了异常,会出现什么问题呢?

乍一想似乎没问题,但仔细一想:Java线程执行时出现异常会导致线程执行中断。

因为Java线程中断了,所以线程不会再向数据库发送「增加订单详情记录、插入物流信息」的SQL,此刻再来想想这个场景,由于增加订单详情和物流信息的SQL都未发送过来,因此必然也不会执行,但此时库存已经扣了,用户钱也付了,但却没有订单和物流信息,这引发的后果估计老板都能杀个程序员祭天了…

其实上面列举的这个案例,在数据库中被称之为事务问题,接下来一起聊一聊。

一、事务的ACID原则

什么是事务呢?事务通常是由一个或一组SQL组成的,组成一个事务的SQL一般都是一个业务操作,例如前面聊到的下单:「扣库存数量、增加订单详情记录、插入物流信息」,这一组SQL就可以组成一个事务。

而数据库的事务一般也要求满足ACID原则,ACID是关系型数据库实现事务机制时必须要遵守的原则。

ACID主要涵盖四条原则,即:

  • A/Atomicity:原子性
  • C/Consistency:一致性
  • I/Isolation:独立性/隔离性
  • D/Durability:持久性

那这四条原则分别是什么意思呢?接下来一起聊一聊。

1.1、Atomicity原子性

原子性这个概念,在MySQL中原子性的含义也大致相同,指组成一个事务的一组SQL要么全部执行成功,要么全部执行失败,事务中的一组SQL会被看成一个不可分割的整体,当成一个操作看待。

好比事务A①、②、③SQL组成,那这一个事务中的三条SQL必须全部执行成功,只要其中任意一条执行失败,例如执行时出现异常了,此时就会导致事务A中的所有操作全部失败。

1.2、Consistency一致性

一致性也比较好理解,也就是不管事务发生的前后,MySQL中原本的数据变化都是一致的,也就是DB中的数据只允许从一个一致性状态变化为另一个一致性状态。这句话似乎听起来有些绕,不太好理解对嘛?简单解释一下就是:一个事务中的所有操作,要么一起改变数据库中的数据,要么都不改变,对于其他事务而言,数据的变化是一致的,上栗子:

假设此时有一个事务A,这个事务隶属于一个下单操作,由「⓵扣库存数量、⓶增加订单详情记录、⓷插入物流信息」三这条SQL操作组成。

一致性的含义是指:在这个事务执行前,数据库中的数据是处于一致性状态的,而SQL执行完成之后事务提交,数据库中的数据依旧处于一个“一致性”状态,也就是库存数量+订单数量永远是等于最初的库存总数的,比如原本的总库存是10000个,此时库存剩余8888个,那也就代表着必须要有1112条订单数据才行。

这也就是前面说的:“事务发生的前后,MySQL中原本的数据变化都是一致的”,这句话的含义,不可能库存减了,但订单没有增加,这样就会导致数据库整体数据出现不一致。

如果出现库存减了,但订单没有增加的情况,就代表着事务执行过程中出现了异常,此时MySQL就会利用事务回滚机制,将之前减的库存再加回去,确保数据的一致性。

但来思考一个问题,如果事务执行过程中,刚减完库存后,MySQL所在的服务器断电了咋整?似乎无法利用事务回滚机制去确保数据一致性了撒?对于这点大可不必担心,因为MySQL宕机重启后,会通过分析日志的方式恢复数据,确保一致性(对于这点稍后再细聊)。

1.3、Isolation独立性/隔离性

简单理解原子性和一致性后,再来看看ACID中的隔离性,在有些地方也称之为独立性,意思就是指多个事务之间都是独立的,相当于每个事务都被装在一个箱子中,每个箱子之间都是隔开的,相互之间并不影响,同样上个栗子:

假设数据库的库存表中,库存数量剩余8888个,此时有A、B两个并发事务,这两个事务都是相同的下单操作,由「⓵扣库存数量、增⓶加订单详情记录、⓷插入物流信息」三这条SQL操作组成。

此时A、B两个事务一起执行,同一时刻执行减库存的SQL,因此这里是并发执行的,那两个事务之间是否会互相影响,导致扣的是同一个库存呢?答案是不会,ACID原则中的隔离性保障了并发事务的顺序执行,一个未完成事务不会影响另外一个未完成事务。

隔离性在底层是如何实现的呢?基于MySQL的锁机制和MVCC机制做到的(后续《MySQL事务与锁原理篇》再详细去讲)。

1.4、Durability持久性

相较于之前的原子性、一致性、隔离性来说,持久性是ACID原则中最容易理解的一条,持久性是指一个事务一旦被提交,它会保持永久性,所更改的数据都会被写入到磁盘做持久化处理,就算MySQL宕机也不会影响数据改变,因为宕机后也可以通过日志恢复数据。

也就相当于你许下一个诺言之后,那你无论遇到什么情况都会保证做到,就算遇到山水洪灾、地球毁灭、宇宙爆炸…任何情况也好,你都会保证完成你的诺言为止。

二、MySQL的事务机制综述

刚刚说到的ACID原则是数据库事务的四个特性,也可以理解为实现事务的基础理论,那接下来一起看看MySQL所提供的事务机制。在MySQL默认情况下,一条SQL会被视为一个单独的事务,同时也无需咱们手动提交,因为默认是开启事务自动提交机制的,如若你想要将多条SQL组成一个事务执行,那需要显式的通过一些事务指令来实现。

2.1、手动管理事务

MySQL中,提供了一系列事务相关的命令,如下:

  • start transaction | begin | begin work:开启一个事务
  • commit:提交一个事务
  • rollback:回滚一个事务

当需要使用事务时,可以先通过start transaction命令开启一个事务,如下:

-- 开启一个事务
start transaction;

-- 第一条SQL语句
-- 第二条SQL语句
-- 第三条SQL语句

-- 提交或回滚事务
commit || rollback;

对于上述MySQL手动开启事务的方式,相信大家都不陌生,但大家有一点应该会存在些许疑惑:事务是基于当前数据库连接而言的,而不是基于表,一个事

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值