概述
文章有点长哟,需要耐心看哟
数据库系统是现代商业世界有序稳定运行的基石,数据和数据承载的交易事件的结果不会因系统故障而损伤。数据库系统的核心技术是事务处理机制,也是有别于其他系统的关键特质。事务处理机制以其ACID特性保证了在各种环境下的数据一致性。同时:数据库系统又是多用户处理系统,为了提高数据库的性能,数据库常常会并发执行多个事务,事务的并发执行,虽然提高了性能,但是却带来了其他的数据一致性问题,因此,合适的并发控制技术是必须的,本文主要介绍MySQL的事务处理和并发控制技术。
1. 数据库事务系统概述
数据库管理系统是位于用户与操作系统之间的一层数据管理软件,数据库的事务处理机制是数据库的基石,那么为什么需要事务处理机制呢?
1.1 为什么需要事务处理机制
我们先看一个问题:账户A转账50元到账户B,过程如下:
事务处理机制就是要通过实现事务的ACID特性来保证用户对数据的操作是安全的一致的,不管在什么环境下,都必须是安全的一致的。事务概念为应用程序开发人员提供了一个非常好的抽象,同时保证了数据的安全一致性。
1.2 什么是事务呢?具有哪些特性
前面我们通过例子简单的认识了事务处理的必要性,那么事务到底是什么呢?它的ACID特性该如何理解呢?
事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成,事务是无法被分割的操作,事务必须作为一个完整的单元成功或失败,不可能存在部分完成的事务。
事务具有如下特性:
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。那么该如何理解这四个特性呢?
- 1.原子性:ACID的原子性描述了当客户想进行多次写入,但在一些写操作处理完之后出现故障的情况。例如进程崩溃,网络连接中断,磁盘变满或者某种完整性约束被违反。如果这些写操作被分组到一个原子事务中,并且该事务由于错误而不能完成(提交),则该事务将被中止,并且数据库必须丢弃或撤消该事务中迄今为止所做的任何写入。如果没有原子性,在多处更改进行到一半时发生错误,很难知道哪些更改已经生效,哪些没有生效。该应用程序可以再试一次,但冒着进行两次相同变更的风险,可能会导致数据重复或错误的数据。原子性简化了这个问题:如果事务被中止(abort),应用程序可以确定它没有改变任何东西,所以可以安全地重试。ACID原子性的定义特征是:能够在错误时中止事务,丢弃该事务进行的所有写入变更的能力。即:可中止的。
- 2.一致性:ACID一致性的概念是,对数据的一组特定陈述必须始终成立。例如我们之前举例的转账。一致性更多的强调的是数据库状态的变迁,即:数据库必须从一个有序状态变迁到另一个有序状态,那么什么是有序的? 答案是:数据在事务的操作下,始终符合用户定义的所有完整性约束。可见:原子性,隔离性和持久性是数据库的属性,而一致性(在ACID意义上)是应用程序的属性。应用可能依赖数据库的原子性、隔离性和持久性来实现数据额一致性。
- 3.隔离性:大多数数据库都会同时被多个客户端访问。如果它们各自读写数据库的不同部分,这是没有问题的,但是如果它们访问相同的数据库记录,则可能会遇到并发问题(竞争条件(race conditions))。如下图显然违背了隔离性:
ACID意义上的隔离性意味着,同时执行的事务是相互隔离的:它们不能相互冒犯。传统的数据库教科书将隔离性形式化为可串行化(Serializability),这意味着每个事务可以假装它是唯一在整个数据库上运行的事务。数据库确保当事务已经提交时,结果与它们按顺序运行(一个接一个)是一样的,尽管实际上它们可能是并发运行的。不过在实际生产环境中,很少使用可串行化,因为这会使得性能大幅降低。
4.持久性:数据库系统的目的是,提供一个安全的地方存储数据,而不用担心丢失。持久性 是一个承诺,即一旦事务成功完成,即使发生硬件故障或数据库崩溃,写入的任何数据也不会丢失。当然了,没有绝对的持久性,如果你的数据所在的磁盘损坏了呢?备份也损坏了呢?因此没有绝对的持久性安全性,增加副本只能增加安全性的几率,但是绝对达不到100%。以上介绍了数据库的四大特性,接下来看看为什么需要并发控制呢?
1.3 为什么需要并发控制
我们已经知道,数据库会同时被多个用户(多个事务)访问,如果多个事务访问不同的数据,那么事务之间不会有任何干扰,如果多个事务操作相同的数据,那么各个事务之前就会互相干扰违背事务的隔离性,导致数据不一致。因此,为了满足隔离性,使得各个并发的事务互不干扰,数据库系统必须对并发的事务进行控制,即:并发控制。
那么不进行并发控制会有哪些问题呢?
事务之间的关系有如下三种:
- 1、读--读:如果多个事务都是只读操作,那么这些事务可以并发,不会互相干扰(因为没有数据更新)。
- 2、读--写:如果读写都存在,则会存在脏读、不可重复度、幻读等问题。
- 3、写--写:如果多个事务并发的写同一数据,如果不加并发控制也会带来数据异常。
接下来看看三种常见的读异常:
如上图:脏读:如果没有并发控制机制,事务T2在Time1处读到了无效的数据(因为事务T1在Time2时中止了)不可重复读:事务T1在Time3处发生了不可重复读(同一个事务,在事务执行的过程中,同一行数据,读到了不同的值)幻读:事务T1在Time3处发生了幻读。
没有并发控制的情况下,读--写操作不仅会造成三种读异常,写写操作也会造成写异常,下边我们看看写-写操作导致的异常:
如上图: 脏写:事务T1在time3时刻回滚掉了不是自己修改的数据,即事务T1在time3出发生了脏写。丢失更新:事务T1在time3处覆盖掉了不是自己修改的数据,即T1在time3出发生了丢失更新异常,如果是T2在time3时提交,道理也是一样的,只不过在T2上发生了丢失更新。
除了以上读写异常,还存在一种**语义约束(事务的特性是要保证语义约束的)**引发的数据异常--写偏序:为了理解写偏序,我们先看一个例子(该例子来自《数据密集型应用系统设计》