数据库事务的方方面面

事务是关系型数据的一个重要特性,但不多有人能对事务有全面性的了解,这篇文章就把事务的方方面面讲给你。sql

事务的概念

什么是事务

数据库事务(事务)是数据库管理系统执行过程当中的一个逻辑单位,由一个有限的数据库操做序列构成。数据库

并发问题

五种并发问题分别是:并发

  • 第一类丢失更新
  • 第二类丢失更新
  • 脏读
  • 不可重复读
  • 幻读

下面依次举例讲解一下。ide

更新丢失(Lost Update)

一个事务覆盖另外一个事务已提交的更新数据叫丢失更新。post

第一类丢失更新:性能

时间 draw money事务 deposit money事务
T1 开始事务
T2 开始事务
T3 查询帐户余额为10,000
T4 查询帐户余额为10,000
T5 存入1,000并修改余额为11,000
T6 提交事务
T7 取出1,000并修改余额为9,000
T8 撤销事务并回滚余额为10,000

最终余额少了1,000。优化

第二类丢失更新:spa

时间 draw money事务 deposit money事务
T1 开始事务
T2 开始事务
T3 查询帐户余额为10,000
T4 查询帐户余额为10,000
T5 取出1,000并修改余额为9,000
T6 提交事务
T7 存入1,000并修改余额为11,000
T8 提交事务

最终余额多了1,000。操作系统

脏读(Dirty Read)

一个事务读取到另外一个事务还没提交的数据叫脏读。日志

例如,事务A修改了一行数据,但没有提交,事务 B读取了被事务A修改后的数据,以后事务A由于某种缘由Rollback了,那么事务B读取的数据就是脏的。

时间 draw money事务 deposit money事务
T1 开始事务
T2 开始事务
T3 查询帐户余额为10,000
T4 取出1,000并修改余额为9,000
T5 查询帐户余额为9,000 (脏读)
T6 撤销事务并回滚余额为10,000
T7 存入1,000并修改余额为11,000
T8 提交事务

不可重复读(NonRepeatable Read)

一个事务前后读到另外一个事务提交以前的数据和已提交的更新数据。

A和B事务并发执行,A事务查询数据,而后B事务更新该数据,A再次查询该数据时,发现该数据变化了。

不可重复读常常发生在updatedelete操做。

时间 draw money事务 deposit money事务
T1 开始事务
T2 开始事务
T3 查询帐户余额为10,000
T4 查询帐户余额为10,000
T5 取出1,000并修改余额为9,000
T6 提交事务
T7 查询帐户余额为9,000
T8 同一个事务两次查询查到的结果不一样

幻读(Phantom Read)

事务在操做过程当中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺乏了第一次查询中出现的数据。

例如,A和B事务并发执行,A事务查询数据,B事务插入或者删除数据,A事务再次查询发现结果集中有之前没有的数据,或者之前有的数据消失了,仿佛出现了幻觉。

幻读常常发生在insert操做。

时间 draw money事务 deposit money事务
T1 开始事务
T2 开始事务
T3 查询帐号数为100,000
T4 注册新帐号
T5 提交事务
T6 查询帐号数为100,001
T7 同一个事务两次查询查到的结果不一样

事务的特性

事务有4个特性,被称为ACID,分别是:

  • 持久性 (Durability)
  • 隔离性 (Isolation)
  • 一致性 (Consistency)
  • 原子性 (Atomicity)

原子性

一个事务(transaction)中的全部操做,要么所有完成,要么所有不完成,不会结束在中间某个环节。

事务在执行过程当中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务历来没有执行过同样。

一致性

在事务开始以前和事务结束之后,数据库的完整性没有被破坏。

即事务先后,数据库的状态都知足全部的完整性约束。

隔离性

数据库容许多个并发事务同时对其数据进行读写和修改的能力,隔离性能够防止多个事务并发执行时因为交叉执行而致使数据的不一致。

事务隔离分为不一样级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

持久性

事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失。

事务的隔离级别

在介绍事务的隔离性的适合提到了事务的4个隔离级别:

  • 未提交读(Read Uncommitted)
  • 已提交读(Read Committed)
  • 可重复读(Repeatable Read)
  • 可串行化(Serializable)

同时事务的隔离级别也与前面提到的5中并发问题有关。隔离级别越高,越能保证数据的完整性和一致性,可是对并发性能的影响也越大。

隔离级别与并发问题:

隔离级别 脏读 不可重复读 幻读
未提交读 可能 可能 可能
已提交读 不可能 可能 可能
可重复读 不可能 不可能 可能
可串行化 不可能 不可能 不可能

对于多数应用程序,能够优先考虑把数据库系统的隔离级别设为Read Committed。它可以避免更新丢失、脏读,并且具备较好的并发性能。尽管它会致使不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,能够由应用程序采用悲观锁或乐观锁来控制。

MySQL InnoDB 默认隔离级别是可重复读(Repeatable read) 。Oracle等数据库默认都是已提交读(Read Committed),即只能读取到已经提交的数据。

读未提交(Read Uncommitted)

读事务不阻塞其余读事务和写事务,未提交的写事务阻塞其余写事务但不阻塞读事务。

此隔离级别能够防止更新丢失,但不能防止脏读、不可重复读、幻读。

读已提交(Read Committed)

读事务容许其余读事务和写事务,未提交的写事务禁止其余读事务和写事务。

读未提交能够防止更新丢失、脏读,但不能防止不可重复读、幻读。

可重复读(Repeatable Read)

以操做同一行数据为前提,读事务禁止其余写事务但不阻塞读事务,未提交的写事务禁止其余读事务和写事务。

此隔离级别能够防止更新丢失、脏读、不可重复读,但不能防止幻读。

可串行化(Serializable)

提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。

此隔离级别能够防止更新丢失、脏读、不可重复读、幻读。

若是仅仅经过“行级锁”是没法实现事务序列化的,必须经过其余机制保证新插入的数据不会被刚执行查询操做的事务访问到。

事务操做

BEGIN

BEGINSTART TRANSACTION :显式开启一个事务。

COMMIT

COMMITCOMMIT WORK : 提交事务,并使已对数据库进行的全部修改为为永久性的。

ROLLBACK

ROLLBACKROLLBACK WORK : 回滚并撤销正在进行的全部未提交的修改。

SAVEPOINT

SAVEPOINT identifier : SAVEPOINT 容许在事务中建立一个保存点,一个事务中能够有多个 SAVEPOINT。

RELEASE SAVEPOINT identifier : 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常。

ROLLBACK

ROLLBACK : 回滚事务。

ROLLBACK TO identifier : 把事务回滚到保存点。

TRANSACTION

SET TRANSACTION : 设置事务的隔离级别。

InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。

AUTOCOMMIT

select @@autocommit : 查看事务自动提交设置。

set autocommit=0 : 设置事务不自动提交。

set autocommit=1 : 设置事务自动提交。

-- 查看事务自动提交设置
select @@autocommit;

-- 设置事务不自动提交
set autocommit=0;

-- 设置事务自动提交
set autocommit=1;
复制代码

事务日志

事务的机制实现很大一部依赖事务日志文件。

事务日志是一个与数据库文件分开的文件。它存储对数据库进行的全部更改,并所有记录插入、更新、删除、提交、回退和数据库模式变化。事务日志还称做前滚日志或重作日志。事务日志是备份和恢复的重要组件。

数据库锁

是数据库事务很重要的一个话题,因为篇幅缘由,咱们这里不展开讲了,下面我会专门提供一篇文章讲解。


Wechat-westcall

相关资源

Wechat-westcall

MySQL系列文章:

相关文章
相关标签/搜索