系列目录
MySQL应用技术1 — MySQL架构简介
MySQL应用技术3 — MVCC
MySQL应用技术4 — 数据类型选择
MySQL应用技术5 — 约束与范式
MySQL应用技术6 — 数据库中的锁
MySQL应用技术7 — 性能优化简析
其实对于事务的概念,想必接触过数据库的同学们多少都有了了解。简单来说表现为一组原子性的SQL语句,或者一个独立的工作单元。在事务内的语句要么全部执行成功,要么全部不执行。
对于事务的定义有如下四个特性:
原子性(Atomicity)
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性(Consistency)
一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。也就是说:如果事务是并发多个,系统也必须如同串行事务一样操作。其主要特征是保护性和不变性(Preserving an Invariant),以转账案例为例,假设有五个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性。
【个人理解的一致性更多是对使用者的要求,要求我们设计事务范围的时候,要保证整体的一致性。其实我们完全可以把一个扣钱就当一个事务去提交,另一个人加钱当作事务提交,就违背了总额500的状态。所以此处更多的是对事务包含范围的约束】
隔离性(Isolation)
隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。
持久性(Durability)
在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
【对于ACID来说,如果要完整的实现,其实是相当困难的,可以说会大大降低数据库的并发能力。特别是对于其中的隔离性,涉及到的了读操作,而大多数应用来说,并不需要严格的隔离性,大部分读多写少的场景也并不需要读写都串行化。因此便有了四种隔离级别以便于用户进行选择设置,可以更挑选更适合自己应用场景的隔离级别(虽然我从来都没有设置过,都是用InnoDB默认的可重复读)】
下面简单介绍下四种隔离级别:
Read Uncommitted(读未提交)
在读未提交的级别下,所有事务都可以看到其他未提交事务的执行结果,这也被称之为脏读。这个隔离级别很少用于实际应用,因为它的性能并不比其他级别好很多,但却缺乏其他级别的好处。
Read Committed(读已提交)
大多数数据库系统的默认隔离级别都是读已提交(但MySQL不是)。它满足一个事务开始时,只能读取到已经提交的事务所做的修改,避免了上个级别所说的脏读问题。但让有不可重复读的问题,即一个事务中执行两次相同的查询可能得到不同的结果。
Repeatable Read(可重读)
这是MySQL的默认事务隔离级别,它确保了一个事务中多次读取同样数据时得到的结果是一致的(避免了不可重复读)。但理论上仍不能解幻读问题,即读取范围数据时会因别的事务对该范围内数据做了插入而导致两次读取范围数据不一致(第二次会多一行,产生幻行)。InnoDB通过多版本并发控制(MVCC)解决了幻读问题。【下一章会详细介绍MVCC】
Serializable(可串行化)
这是最高的隔离级别。它通过强制事务排序,使之不可能相互冲突,从而避免了幻读问题。简单来说,串行化会在每一行数据上都加锁,所以可能导致大量的超时和锁竞争。只有在非常需要保证数据的一致,并且几乎没有并发的情况,才考虑使用该级别。
【所以这就是为啥我从来不设置,就用默认的。默认的这个隔离级别就可以适用于绝大多数场景,对于业务内极个别需要处理并发操作的场景,可以考虑使用分布式锁来解决,而非设置串行化的隔离级别】
【说道这个隔离级别和竞争这些问题,自然就有绕不开锁的概念,上一章也提到行锁,表锁,读写锁等等。跟多线程并发一样,如果搞不好,也会导致数据库的死锁。如果死锁了可咋整,难道就挂掉吗?其实MySQL有一套超时监测机制,发现如果等待某个锁的时间超过一定的限制,就会回滚当前事务。当然对于比较好的存储引擎,比如说我们经常用的InnoDB(所以为啥用它呢,就是好啊),也具有了循环依赖的检测能力,当发现死锁是由循环依赖导致的时候,会选择持有最少行级排它锁的事务进行回滚。】
至于像数据库中使用的两段锁定协议,行锁、表锁、间隙锁等等也会在后序的章节讲到。
对于显示的加锁,MySQL支持以
SELECT ..... LOCK IN SHARE MODE
SELECT ..... FOR UPDATE
进行显示加共享锁或者排它锁。但这都是在服务器端实现的(服务器端概念:
MySQL应用技术1 — MySQL架构简介),和存储引擎无关。他们有自己的用途,并不能代替事务处理。如果应用需要用到事务,还是应该选择事务型存储引擎
【嗯,选InnoDB】
文中【斜体】部分多为个人理解,不足支持还望指正。
欢迎注明出处及本文链接的转载。