MySQL 数据库事务
数据库事务特性
事务是由一组 SQL 语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的 ACID 属性。
- 原子性(Atomicity):是指事务由原子的操作序列组成,所有操作要么全部成功,要么全部失败回滚。
- 一致性(Consistent):是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处以一致性状态。比如在做多表操作时,多个表要么都是事务后新的值,要么都是事务前的旧值。事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
- 隔离性(Isolation) :是指多个用户并发访问数据库时,数据库为每个用户执行的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。事务的隔离级别我们稍后介绍。数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
- 持久性(Durable):是指一个事务一旦提交并执行成功,那么对数据库中数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
事务并发带来的问题
- 更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。
- 脏读(Dirty Reads):脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据,例如,账户A转帐给B500元,B余额增加后但事务还没有提交完成,此时如果另外的请求中获取的是B增加后的余额,这就发生了脏读,因为事务如果失败回滚时,B的余额就不应该增加。一句话:事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求。
- 不可重读(Non-Repeatable Reads) :不可重复读是指对于数据库中某个数据,一个事务范围内多次查询返回了不同的数据值,这是由于在多次查询之间,有其他事务修改了数据并进行了提交。一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做不可重复读。一句话:事务A读取到了事务B已经提交的修改数据,不符合隔离性
- 幻读(Phantom Reads):是指一个事务中执行两次完全相同的查询时,第二次查询所返回的结果集跟第一个查询不相同。与不可重复读的区别在于,不可重复读是对同一条记录,两次读取的值不同。而幻读是记录的增加或删除,导致两次相同条件获取的结果记录数不同。一句话:事务A读取到了事务B提交的新增数据,不符合隔离性
解决事务并发问题的事务隔离
脏读、不可重复读 和 幻读,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。
隔离级别 | 脏读(Dirty Reads) | 不可重读(Non-Repeatable Reads) | 幻读(Phantom Reads) |
---|---|---|---|
读未提交(read uncommitted) | 可能 | 可能 | 可能 |
读已提交(read committed) | 不可能 | 可能 | 可能 |
可重复度(repeatable read) | 不可能 | 不可能 | 可能 |
串行化(serializable) | 不可能 | 不可能 | 不可能 |
- 级别1 读未提交:也就是可以读取到其他事务未提交的内容,这是最低的隔离级别,这个隔离级别下,前面提到的三种并发问题都有可能发生。
- 级别2 读已提交:就是只能读取到其他事务已经提交的数据。这个隔离级别可以解决脏读问题。
- 级别三可重复读:可以保证整个事务过程中,对同数据的多次读取结果是相同的。这个级别可以解决脏读和不可重复读的问题。MySQL默认的隔离级别就是可重复读。
- 级别四串行化:这是最高的隔离级别,所有事务操作都依次顺序执行。这个级别会导致并发度下降,性能最差。不过这个级别可以解决前面提到的所有并发问题。
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。
同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读"和“幻读”并不敏感,可能更关心数据并发访问的能力。
常看当前数据库的事务隔离级别:
show variables like 'tx_isolation';
设置事务隔离级别:
set tx_isolation='REPEATABLE-READ';
事务分类
- 扁平化事务:在扁平事务中,所有的操作都在同一层次,这也是我们平时使用最多的一种事务。它的主要限制是不能提交或者回滚事务的某一部分,要么都成功,要么都回滚。
- 带保存点的扁平事务:为了解决第一种事务的弊端,就有了第二种带保存点的扁平事务。它允许事务在执行过程中回滚到较早的状态,而不是全部回滚。通过在事务中插入保存点,当操作失败后,可以选择回滚到最近的保存点处。
- 链事务:可以看做是第二种事务的变种。它在事务提交时,会将必要的上下文隐式传递给下一个事务,当事务失败时就可以回滚到最近的事务。不过,链事务只能回滚到最近的保存点,而带保存点的扁平化事务是可以回滚到任意的保存点。
- 嵌套事务:由顶层事务和子事务构成,类似于树的结构。一般顶层事务负责逻辑管理,子事务负责具体的工作,子事务可以提交,但真正提交要等到父事务提交,如果上层事务回滚,那么所有的子事务都会回滚。
- 分布式事务:是指分布式环境中的扁平化事务。
分布式事务
- XA 协议:是保证强一致性的刚性事务。实现方式有两段式提交和三段式提交。两段式提交需要有一个事务协调者来保证所有的事务参与者都完成了第一阶段的准备工作。如果协调者收到所有参与者都准备好的消息,就会通知所有的事务执行第二阶段提交。一般场景下两段式提交已经能够很好得解决分布式事务了,然而两阶段在即使只有一个进程发生故障时,也会导致整个系统存在较长时间的阻塞。三段式提交通过增加 Pre-commit 阶段来减少前面提到的系统阻塞的时间。三段式提交很少在实际中使用,简单了解就可以了。
- TCC:是满足最终一致性的柔性事务方案。TCC 采用补偿机制,核心思想是对每个操作,都要注册对应的确认和补偿操作。它分为三个阶段:Try阶段主要对业务系统进行检测及资源预留;Confirm 阶段对业务系统做确认提交。Cancel 阶段是在业务执行错误,执行回滚,释放预留的资源。
- 消息事务:第三种方案是消息一致性方案。基本思路是将本地操作和发送消息放在一个事务中,保证本地操作和消息发送要么都成功要么都失败。下游应用订阅消息,收到消息后执行对应操作。
- GTS/Fescar:阿里云中的全局事务服务 GTS,对应的开源版本是 Fescar。Fescar 基于两段式提交进行改良,剥离了分布式事务方案对数据库在协议支持上的要求。使用Fescar 的前提是分支事务中涉及的资源,必须是支持 ACID 事务的关系型数据库。分支的提交和回滚机制,都依赖于本地事务来保障。 Fescar 的实现目前还存在一些局限,比如事务隔离级别最高支持到读已提交级别。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: MySQL 数据类型
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论