BREAK IN TO BREAK OUT Lyn
  1. 1 BREAK IN TO BREAK OUT Lyn
  2. 2 かかってこいよ NakamuraEmi
  3. 3 Warcry mpi
  4. 4 Life Will Change Lyn
  5. 5 Libertus Chen-U
  6. 6 Last Surprise Lyn
  7. 7 Hypocrite Nush
  8. 8 Flower Of Life 发热巫女
  9. 9 One Last You Jen Bird
  10. 10 Time Bomb Veela
2019-10-19 13:05:22

初识事务隔离

事务这个概念也不陌生了, react和mobx中都多次了解过了,在MySQL里的事务也是一样的,就是为了保证操作的完整性以及数据的一致性。这篇文章就学习一下MySQL的事务设计。

事务的特性

严格的说,事务并不是MySQL的设计。因为MySQL的存储引擎是插件式的,原生引擎MyISAM是不支持事务的,支持事务的是默认的InnoDB引擎,这也算是InnoDB能取代MyISAM的原因之一了。进入到InnoDB的事务细节之前,还是先概览下事务的4个特性,也就是业界常谈的到的ACID。

  • A:原子性(Ayomicty)。正如原子不可分割一样,事务是作为数据操作的基本单位,要么成功要么失败,不可能只完成事务中的一部分操作。
  • C:一致性(Consistency)。这个有点类似React的state,事务提交成功的数据库状态变化就相当于setState后组件状态变化,数据库的状态总是从一个正确的状态转移到另外一个正确的状态。这个更像是事务本身达到的目的,而不是事务操作的特征,事务通过AID三个特征能达到C这个目的。
  • I:隔离性(iIsolation)。事务之间相互独立,每个事务在提交前,对其他事务都不可见。
  • D:持久性(Durablity)。持久这个概念不太好理解,咋一看感觉像是事务一个长时间的操作,我认为应该指的是事务操作的结果具有持久性,在一个持续的时间长度内,可以在数据库中被追溯到的意思。比如数据库崩溃的话,如果事务操作的数据还在持久性允许的时间范围内,就可以被安全找回。保证这一点的设计也就是上一篇文章中讲到的日志了。

事务的操作

隐式事务

类比React中的事务,InnoDB中的绝大多数用户操作也都处于事务中,并且事务对于用户使用上来说也是无感知的,也就是隐式事务了。DML操作的语句都会隐式的开启事务,并且在语句执行后没有错误的话隐式提交。

可以通过将MySQL的autocommit这个变量(默认为1)设置为0将事务的隐式提交关闭,但需要注意,DML语句的隐式事务仍会启动,只是区别在于需要手动COMMIT显式提交这个事务,也就是将隐式事务转化为长事务了。

mysql> show variables like 'autocommit';  // 通过该语句查看隐式事务提交方式
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+

显式事务

显式操作事务时,常用的控制语句如下:

  • START TRANSSACTION或者BEGIN:显式开启一个事务
  • COMMIT:提交事务
  • ROLLBACK:回滚事务
  • SAVEPOINT:在事务中创建保存点,可以在同一事务中创建多个,以便通过ROLLBACK更灵活的回滚

显式开启一个事务时,如果还有未提交的事务会自动提交,并且autocommit会被禁用直到该事务结束。对于显式事务,存在completion_type这样一个变量控制显式事务的行为。有下列三种情况:

  • 值为0时即为默认,执行COMMIT后提交该显式事务并结束该事务。
  • 值为1时,执行COMMIT后除了有值为0时的默认行为外,随后会自动开始一个相同隔离级别的事务。术语为COMMIT AND CHAIN
  • 值为2时,执行COMMIT后除了有值为0时的默认行为外,随后会断开与服务器的连接。术语为COMMIT AND RELEASE

事务隔离

事务设计的本意很大一部分是为了解决并发操作时造成的数据不一致状况,那么首先得知道,并发处理会带来哪些问题?实际上MySQL已经对并发带来的数据异常问题做了官方定义如下:

  • 脏读:读到了其他事务还未提交的数据。

    比如当A事务往表1写入一条新的数据data1,还未提交该数据时,B事务查询却在表1中查询到了data1,就叫脏读。

  • 不可重复读:一个事务查询同一条记录两次,得到结果不一致。

    比如当A事务第一次查询表1后得到结果后并未COMMIT,B事务更新了表1的数据,A事务再查询一次得到结果相比第一次有不一样,就叫不可重复读。

  • 幻读:一个事务中先查询一次得到结果,再插入基于该结果不存在的数据时,发现该数据已存在,就如同幽灵数据一样。

    比如A事务查询表1得到结果后并未COMMIT,B事务在表1中新增了数据data1,A事务继续插入同一条数据data1,发现执行错误,data1已经在表1中了,就叫幻读。

    不可重复读和幻读比较类似,但侧重点不一样,前者是读和读之间产生的差别,后者是读和写之间产生的差别。

为了解决上述的并发问题,事务就有了一些设计来实现ACID中的I——隔离性。但隔离越严格,数据库效率就会越低,不同场景下对数据的准确度要求和效率要求有权衡,需要的隔离程度也不一样。所以为了给使用者一个平衡点,MySQL设置了4种事务隔离级别,不同级别能解决的并发问题也不一样,具体如下表。

  • 读未提交:允许读到未提交的数据。一个事务还未提交时,其他事务就能感知到该事务做的变更。
  • 读提交:只允许读到已提交的数据。一个事务提交之后,其造成的变更才能被其他事务感知。这是Oracle默认的隔离等级。
  • 可重复读:一个事务中能读到的数据总是和该事务开启时能读到的数据是一致的。这也是MySQL默认的隔离等级。
  • 可串行化:将事务置于队列中按顺序执行。算是一种极端,拥有最高的隔离等级,能解决所有并发异常,因为舍弃了并发。

同样的,隔离等级也可以通过transaction-isolation设置。

mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+

小结

以上就是MySQL中事务的一些常见操作和表现,既然是"初识"就写到这里,但搞清楚事务隔离的设计原理也是很重要的,不过又会涉及到另外一个关键知识点——锁。原理的相关分析就留到介绍了锁之后吧。

-- EOF --

添加在分类「 前端开发 」下,并被添加 「数据库」 标签。