[MySQL进阶]——数据库事务概述
笔记整理自 【宋红康】MySQL数据库(mysql安装/基础/高级/优化),并从《mysql是怎样运行的》作为补充
数据库事务概述
存储引擎支持情况
SHOW ENGINES 命令来查看当前 MySQL 支持的存储引擎都有哪些,以及这些存储引擎是否支持事务
能看出在 MySQL 中,只有InnoDB 是支持事务的。
基本概念
事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。
事务处理的原则:保证所有事务都作为 一个工作单元 来执行,即使出现了故障,都不能改变这种执行方 式。当在一个事务中执行多个操作时,要么所有的事务都被提交( commit ),那么这些修改就 永久 地保 存下来;要么数据库管理系统将 放弃 所作的所有 修改 ,整个事务回滚( rollback )到最初状态。
事务的ACID特性
原子性(atomicity)
原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。
一致性(consistency)
根据定义,一致性是指事务执行前后,数据从一个 合法性状态 变换到另外一个 合法性状态 。这种状态 是 语义上 的而不是语法上的,跟具体的业务有关。
那什么是合法的数据状态呢?满足 预定的约束 的状态就叫做合法的状态。通俗一点,这状态是由你自己 来定义的(比如满足现实世界中的约束)。满足这个状态,数据就是一致的,不满足这个状态,数据就 是不一致的!如果事务中的某个操作失败了,系统就会自动撤销当前正在执行的事务,返回到事务操作 之前的状态。
隔离型(isolation)
事务的隔离性是指一个事务的执行 不能被其他事务干扰 ,即一个事务内部的操作及使用的数据对 并发 的 其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是 永久性的 ,接下来的其他操作和数据库 故障不应该对其有任何影响。
持久性是通过 事务日志 来保证的。日志包括了 重做日志 和 回滚日志 。当我们通过事务对数据进行修改 的时候,首先会将数据库的变化信息记录到重做日志中,然后再对数据库中对应的行进行修改。这样做 的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执 行,从而使事务具有持久性。
事务的状态
我们现在知道 事务 是一个抽象的概念,它其实对应着一个或多个数据库操作,MySQL根据这些操作所执 行的不同阶段把 事务 大致划分成几个状态:
活动的(active)
事务对应的数据库操作正在执行过程中时,我们就说该事务处在 活动的 状态。
部分提交的(partially committed)
当事务中的最后一个操作执行完成,但由于操作都在内存中执行,所造成的影响并 没有刷新到磁盘 时,我们就说该事务处在 部分提交的 状态。
失败的(failed)
当事务处在 活动的 或者 部分提交的 状态时,可能遇到了某些错误(数据库自身的错误、操作系统 错误或者直接断电等)而无法继续执行,或者人为的停止当前事务的执行,我们就说该事务处在 失 败的 状态。
中止的(aborted)
如果事务执行了一部分而变为 失败的 状态,那么就需要把已经修改的事务中的操作还原到事务执 行前的状态。换句话说,就是要撤销失败事务对当前数据库造成的影响。我们把这个撤销的过程称 之为 回滚 。
当 回滚 操作执行完毕时,也就是数据库恢复到了执行事务之前的状态,我们就说该事 务处在了 中止的 状态。
提交的(committed)
当一个处在 部分提交的 状态的事务将修改过的数据都 同步到磁盘 上之后,我们就可以说该事务处 在了 提交的 状态。
如何使用事务
显式事务
步骤
1、步骤1: START TRANSACTION 或者 BEGIN ,作用是显式开启一个事务。
mysql> BEGIN;
#或者
mysql> START TRANSACTION
START TRANSACTION 语句相较于 BEGIN 特别之处在于,后边能跟随几个 修饰符 :
① READ ONLY :标识当前事务是一个 只读事务 ,也就是属于该事务的数据库操作只能读取数据,而不 能修改数据。
② READ WRITE :标识当前事务是一个 读写事务 ,也就是属于该事务的数据库操作既可以读取数据, 也可以修改数据。
③ WITH CONSISTENT SNAPSHOT :启动一致性读。
2、步骤2:一系列事务中的操作(主要是DML,不含DDL)
3、步骤3:提交事务 或 中止事务(即回滚事务)
# 提交事务。当提交事务后,对数据库的修改是永久性的。
mysql> COMMIT;
```mysql
# 回滚事务。即撤销正在进行的所有没有提交的修改
mysql> ROLLBACK;
# 将事务回滚到某个保存点。
mysql> ROLLBACK TO [SAVEPOINT]
保存点
是在事务对应的数据库语句中 “打"几个点 我们在调用 ROLLBACK 语句时可以指定回滚到哪个点,而不是回到最初的原点。
- 定义保存点的语法如下:
SAVEPOINT 保存点名称;
- 当想回滚到某个保存点时
ROLLBACK [WORK] TO [SAVEPOINT] 保存点名称
如果 ROLLBACK 语句后面不跟随保存点名称,则直接回滚到事务执行之前的状态.
- 想删除某个保存点
RELEASE SAVEPOINT 保存点名称;
举例:
BEGIN;
UPDATE user3 SET balance = balance - 100 WHERE NAME = '张三';
UPDATE user3 SET balance = balance - 100 WHERE NAME = '张三';
SAVEPOINT s1;#设置保存点
UPDATE user3 SET balance = balance + 1 WHERE NAME = '张三';
ROLLBACK TO s1; #回滚到保存点
隐式事务
MySQL中有一个系统变量autocommit,用来自动提交事务。
关闭自动提交
显式的的使用 START TRANSACTION 或者 BEGIN 语句开启一个事务。这样在本次事务提交或者回 滚前会暂时关闭掉自动提交的功能。
把系统变量 autocommit 的值设置为 OFF
SET autocommit = OFF; #或 SET autocommit = 0;
隐式提交数据的情况
定义或修改数据库对象的数据定义语言
例如使用 CREATE ALTE DROP 等语句修改这些数据库对象
隐式使用或修改mysql数据库中的表
在使用ALTER USER,CREATE USER,DROP USER,GRANT,RENAME USER,REVOKE,SET PASSWORD等语句时,也会隐式地提交前面语句所属的事务。
事务控制或关于锁定的语句。
当我们在一个事务还没提交或者回滚时就又使用 START TRANSACTION 或者 BEGIN 语句开启了 另一个事务时,会 隐式的提交 上一个事务
当前的 autocommit 系统变量的值为 OFF ,我们手动把它调为 ON 时,也会 隐式的提交 前边语 句所属的事务。
使用 LOCK TABLES 、 UNLOCK TABLES 等关于锁定的语句也会 隐式的提交 前边语句所属的事 务。
加载数据的语句
比如使用LOAD DATA语句向数据库中批量导入数据时,也会隐式地提交前面语句所属的事务。
关于MySQL复制的一些语句。
其他语句。
使用ANALYZE TABLE,CACHE INDEX,CHECK TABLE,FLUSH,LOAD INDEX INTO CACHE,OPTIMIZE TABLE,REPAIR TABLE,RESET等语句时也会隐式地提交前面语句所属的事务。
当我们设置 autocommit=0 时,不论是否采用 START TRANSACTION 或者 BEGIN 的方式来开启事 务,都需要用 COMMIT 进行提交,让事务生效,使用 ROLLBACK 对事务进行回滚。 当我们设置 autocommit=1 时,每条 SQL 语句都会自动进行提交。 不过这时,如果你采用 START TRANSACTION 或者 BEGIN 的方式来显式地开启事务,那么这个事务只有在 COMMIT 时才会生效, 在 ROLLBACK 时才会回滚。
事务隔离级别
概念:
事务有 隔离性 的特性,理论上在某个事务 对某个数据进行访问 时,其他事务应该进行 排 队 ,当该事务提交之后,其他事务才可以继续访问这个数据。
数据并发问题
访问相同数据的事务在 不保证串行执行 (也 就是执行完一个再执行另一个)的情况下可能会出现以下问题:
1、脏写( Dirty Write )
如果事务Session A 修改了 另一个 未提交 事务Session B 修改过 的数 据,那就意味着发生了 脏写
2、脏读( Dirty Read )
Session A 读取 了已经被 Session B 更新 但还 没有被提交 的字段。 之后若 Session B 回滚 ,Session A 读取 的内容就是 临时且无效 的。这种现象 就称之为 脏读 。
3、不可重复读( Non-Repeatable Read )
Session A 读取 了一个字段,然后 Session B 更新 了该字段。 之后 Session A 再次读取 同一个字段, 值就不同 了。那就意味着发生了不可重复读。
4、幻读( Phantom )
Session A 从一个表中 读取 了一个字段, 然后 Session B 在该表中 插 入 了一些新的行。 之后, 如果 Session A 再次读取 同一个表, 就会多出几行。那就意味着发生了幻读。
不可重复读侧重于修改,幻读侧重于新增或删除
SQL标准 中规定,针对不同的隔离级别,并发事务可以发生不同严重程度的问题,具体情况如下:
事务隔离级别与并发性能的关系
MySQL支持的四种隔离级别
MySQL的默认隔离级别为REPEATABLE READ,我们可以手动修改一下事务的隔离级别。
# 查看隔离级别,MySQL 5.7.20的版本之前:
mysql> SHOW VARIABLES LIKE 'tx_isolation';
# 查看隔离级别,MySQL 5.7.20的版本及之后:
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
#或者不同MySQL版本中都可以使用的:
SELECT @@transaction_isolation;
设置事务的隔离级别
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 隔离级别;
#其中,隔离级别格式:
> READ UNCOMMITTED
> READ COMMITTED
> REPEATABLE READ
> SERIALIZABLE
或者:
SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = '隔离级别'
#其中,隔离级别格式:
> READ-UNCOMMITTED
> READ-COMMITTED
> REPEATABLE-READ
> SERIALIZABLE
关于设置时使用GLOBAL或SESSION的影响:
1、使用 GLOBAL 关键字(在全局范围影响):
- 当前已经存在的会话无效
- 只对执行完该语句之后产生的会话起作用
2、使用 SESSION 关键字(在会话范围影响):
- 对当前会话的所有后续的事务有效
- 如果在事务之间执行,则对后续的事务有效
- 该语句可以在已经开启的事务中间执行,但不会影响当前正在执行的事务