天天看点

数据库事务特性和隔离级别

1. 事务的定义

  数据库事务是数据库管理系统执行过程中的一个逻辑单位,有一个有限的数据库操作序列完成。以 “A账户向B账户汇钱” 为例,一个事务是下面一个操作序列:

  a. 从A账号中把余额读出来。

  b. 对A账号做减法操作。

  c. 把结果写回A账号中。

  d. 从B账号中把余额读出来。

  e. 对B账号做加法操作。

  f.  把结果写回B账号中。

2.事务的特性(ACID)

  事务有四大特征,分别为原子性(Atomic),一致性(Consistency),隔离性(Isolation),持久性(Durability)。

原子性(Atomic):

事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败回滚。事务的原子性也体现在事务对数据的读取上,例如一个事务对同一数据项的多次读取的结果一定是相同的。

一致性(Consistency):

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。比如,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

有些时候这种一致性由数据库的内部规则保证,例如数据的类型必须正确,数据值必须在规定的范围内,等等。

另外一些时候这种一致性由应用保证的,例如,** 一般情况下银行账务余额不能是负数,信用卡消费不能超过该卡的信用额度等。**

隔离性(Isolation):

事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。

同时,并行事务的修改必须与其他并行事务的修改相互独立。

事务的隔离性一般由事务的锁来进行控制。

许多时候数据库在并发执行多个事务,每个事务可能需要对多个表进行修改和查询,与此同时,更多的查询请求可能要在执行。数据库需要保证每一个事务在它的修改全部完成之前,对其他的事务是不可见的。

换句话说,不能让其他事务看到该事务的中间状态,例如,从银行账户A转一比款项a到账户B,不能让其他事务(例如账户查询)看到A账户已经扣除款项a但B账户却没有增加款项a的状态。

持久性(Durability):

事务结束后,事务处理的结果必须能够得到固化,即使系统出现各种异常也是如此。

即一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

3.数据库的隔离级别

在多线程并发的环境下,当有多个线程都开启事务操作数据库中的数据时,数据库系统要能够进行隔离操作,以确保各个线程获取数据的准确性。否则,可能会出现以下几种问题:

  • 更新丢失(Lost Update)

当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题——最后的更新覆盖了其他事务所做的更新。例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改保存其更改副本的编辑人员覆盖另一个编辑人员所做的修改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题。通常,“更新丢失”在并发事务处理中通常是完全避免的。

  • 脏读(Dirty Reads)

脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。

当一个事务正在多次修改某个数据,而在这个事务中这多次修改还都未提交时,一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。

  • 不可重复读(Non-Repeatable Reads)

不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,数据被另一个事务修改并提交了。

不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读是读取了前一个事务提交了的数据。

  • 幻读(虚读)(Phantom Reads)

幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

幻读和不可重复读都是读取了另一条已经提交的事务(脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批整体数据。

接下来看看MySQL提供的四种隔离级别:

  1. Serializable(串行化):可避免脏读、不可重复读、幻读的发生
  2. Repeatable read(可重复读):可避免脏读、不可重复读的发生
  3. Read committed(读已提交):可避免脏读的发生
  4. Read uncommitted(读未提交):最低级别,无法避免

这四种级别最高的是Serializable,最低的是Read uncommitted,级别越高,执行效率越低。MySQL的默认级别为Repeatable Read.

需要注意的是,这四种级别都要求当一个事务在进行写操作时,不允许其他事务进行写操作,可通过“排他写锁”实现。

实现这四种隔离级别需要采取不同类型的锁,本文只关心事务特性和隔离级别,关于如何实现隔离级别,将在后续的文章中探讨。

继续阅读