事务是关系型数据的一个重要特性,但不多有人能对事务有全面性的了解,这篇文章就把事务的方方面面讲给你。sql
数据库事务(事务)是数据库管理系统执行过程当中的一个逻辑单位,由一个有限的数据库操做序列构成。数据库
五种并发问题分别是:并发
下面依次举例讲解一下。ide
一个事务覆盖另外一个事务已提交的更新数据叫丢失更新。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。操作系统
一个事务读取到另外一个事务还没提交的数据叫脏读。日志
例如,事务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 | 提交事务 |
一个事务前后读到另外一个事务提交以前的数据和已提交的更新数据。
A和B事务并发执行,A事务查询数据,而后B事务更新该数据,A再次查询该数据时,发现该数据变化了。
不可重复读常常发生在update
和delete
操做。
时间 | draw money事务 | deposit money事务 |
---|---|---|
T1 | 开始事务 | |
T2 | 开始事务 | |
T3 | 查询帐户余额为10,000 | |
T4 | 查询帐户余额为10,000 | |
T5 | 取出1,000并修改余额为9,000 | |
T6 | 提交事务 | |
T7 | 查询帐户余额为9,000 | |
T8 | 同一个事务两次查询查到的结果不一样 |
事务在操做过程当中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺乏了第一次查询中出现的数据。
例如,A和B事务并发执行,A事务查询数据,B事务插入或者删除数据,A事务再次查询发现结果集中有之前没有的数据,或者之前有的数据消失了,仿佛出现了幻觉。
幻读常常发生在insert
操做。
时间 | draw money事务 | deposit money事务 |
---|---|---|
T1 | 开始事务 | |
T2 | 开始事务 | |
T3 | 查询帐号数为100,000 | |
T4 | 注册新帐号 | |
T5 | 提交事务 | |
T6 | 查询帐号数为100,001 | |
T7 | 同一个事务两次查询查到的结果不一样 |
事务有4个特性,被称为ACID
,分别是:
一个事务(transaction)中的全部操做,要么所有完成,要么所有不完成,不会结束在中间某个环节。
事务在执行过程当中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务历来没有执行过同样。
在事务开始以前和事务结束之后,数据库的完整性没有被破坏。
即事务先后,数据库的状态都知足全部的完整性约束。
数据库容许多个并发事务同时对其数据进行读写和修改的能力,隔离性能够防止多个事务并发执行时因为交叉执行而致使数据的不一致。
事务隔离分为不一样级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失。
在介绍事务的隔离性的适合提到了事务的4个隔离级别:
同时事务的隔离级别也与前面提到的5中并发问题有关。隔离级别越高,越能保证数据的完整性和一致性,可是对并发性能的影响也越大。
隔离级别与并发问题:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读 | 可能 | 可能 | 可能 |
已提交读 | 不可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 可能 |
可串行化 | 不可能 | 不可能 | 不可能 |
对于多数应用程序,能够优先考虑把数据库系统的隔离级别设为Read Committed。它可以避免更新丢失、脏读,并且具备较好的并发性能。尽管它会致使不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,能够由应用程序采用悲观锁或乐观锁来控制。
MySQL InnoDB 默认隔离级别是可重复读(Repeatable read) 。Oracle等数据库默认都是已提交读(Read Committed),即只能读取到已经提交的数据。
读事务不阻塞其余读事务和写事务,未提交的写事务阻塞其余写事务但不阻塞读事务。
此隔离级别能够防止更新丢失,但不能防止脏读、不可重复读、幻读。
读事务容许其余读事务和写事务,未提交的写事务禁止其余读事务和写事务。
读未提交能够防止更新丢失、脏读,但不能防止不可重复读、幻读。
以操做同一行数据为前提,读事务禁止其余写事务但不阻塞读事务,未提交的写事务禁止其余读事务和写事务。
此隔离级别能够防止更新丢失、脏读、不可重复读,但不能防止幻读。
提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。
此隔离级别能够防止更新丢失、脏读、不可重复读、幻读。
若是仅仅经过“行级锁”是没法实现事务序列化的,必须经过其余机制保证新插入的数据不会被刚执行查询操做的事务访问到。
BEGIN
或 START TRANSACTION
:显式开启一个事务。
COMMIT
或 COMMIT WORK
: 提交事务,并使已对数据库进行的全部修改为为永久性的。
ROLLBACK
或 ROLLBACK WORK
: 回滚并撤销正在进行的全部未提交的修改。
SAVEPOINT identifier
: SAVEPOINT 容许在事务中建立一个保存点,一个事务中能够有多个 SAVEPOINT。
RELEASE SAVEPOINT identifier
: 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常。
ROLLBACK
: 回滚事务。
ROLLBACK TO identifier
: 把事务回滚到保存点。
SET TRANSACTION
: 设置事务的隔离级别。
InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。
select @@autocommit
: 查看事务自动提交设置。
set autocommit=0
: 设置事务不自动提交。
set autocommit=1
: 设置事务自动提交。
-- 查看事务自动提交设置
select @@autocommit;
-- 设置事务不自动提交
set autocommit=0;
-- 设置事务自动提交
set autocommit=1;
复制代码
事务的机制实现很大一部依赖事务日志文件。
事务日志是一个与数据库文件分开的文件。它存储对数据库进行的全部更改,并所有记录插入、更新、删除、提交、回退和数据库模式变化。事务日志还称做前滚日志或重作日志。事务日志是备份和恢复的重要组件。
锁
是数据库事务很重要的一个话题,因为篇幅缘由,咱们这里不展开讲了,下面我会专门提供一篇文章讲解。
MySQL系列文章: