MySQL中的事务(MySQL8版本)
定义
数据库事务(Transaction)是访问并可能操作各种数据项的一个数据库操作的序列,是一个不可分割的工作单位。 事务是由事务开始与事务结束之间执行的全部数据库操作。
在MySQL当中是只有InnoDB引擎的数据库或表是支持事物的。事务处理可以用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部都不执行。
使用用来的管理语句都包含有INSERT、UPDATE、DELETE语句。
特性
一般来说,事务是必须满足4个条件的(ACID): 原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,或称独立性)、持久性(Durability)。
1. 原子性(Atomicity)
一个事务(Transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间的某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的某个状态,就像这个事务从来没有执行过一样。
举例:张三向李四转账100块,但突然断电,张三已经转出去了100快,但李四并没有收到钱,这样就产生了较大的问题。所以就要解决此类的问题。 解决这个问题就是数据库的原子性,规定要么这两件事都执行了,要么这两件事都没有执行。
2. 持久性(Durability)
持久性即就是当一个事务提交后,对数据的改变是永久性的,是不会被回滚的。
就是除过正常的增删改等操作以外,即使系统故障这些意外都不会让数据库的数据改变或丢失。
3. 隔离性(Isolation)
数据库是允许多个并发事务同时对其进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉而导致数据的不一致。事务隔离分为不同级别的,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
4. 一致性(Consistency)
就是在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的数据时必须符合所有的预测规则。
例子:比如上面转钱的列子,就必须保证传出传入的金额必须一致。
一致性就是前三种特性的集合
隔离性中对并发事务处理时的问题
当两个或者多个事务选择表中同一行进行操作的时候,然后基于最初的选定的值进行更新操作时,由于每个事务都不知道其他事务的存在,所以就会发生丢失更新的问题,即最后的更新并覆盖了前一个程序所做的更改。
事务之间相互影响的种类: 脏读 不可重复读 幻读 丢失更新
假设有两个事务A和B,同时并发:
脏读
一个事务读取了另一个事务未提交的数据
比如,数据表中id为1行的age本身为18;
①事务A修改了id为1的age数据为20
②然后事务B立刻读取了id为1的行数据
③但是事务A在这时发生了事务回滚,返回了id为1行的age数据为18。
显然这样的情况是很不合理的。
不可重复读
在事务A中先后两次读取同一数据,但两次读取的结果是不一样的,这种现象称为不可重复读。
脏读与不可重复读的区别:前者读到的是其他事务未提交的数据,后者读到的其他事务已提交的数据。
在一个事务当中,两次读取的结果不一样这显然也是不可以的。是我们所不能接受的现象。
这就叫做幻读:在同一个事务中两次读取到的数据量不一致。一般幻读出现在范围查询。
幻读
就是指当事务不是独立执行时发生的一种现象
例如:在事务A中按照某个条件进行先后两次的查询,但是两次查询结果的条数是不同的,这种现象称为幻读。
不可重复读与幻读的区别:前者是查的数据中的某个数据变了,后者是前后查询出来的行数变了。
事务的设置
默认情况下,MySQL启用的是自动提交模式(变量 autocommit 为 ON)。这就意味着,只要你执行了DML(数据库操作语言)操作语句,MySQL会立即隐式的提交事务。
由于变量autocommit分会话系统变量与全局系统变量,所以查询的时候,最好区别是会话系统变量还是全局系统变量。
1. 在SQL中查询autocommit模式:
SHOW SESSION(会话) / GLOBAL(全局) VARIABLES LIKE 'autocommit';
SHOW GLOBAL VARIABLES LIKE 'autocommit';
默认它是开启的。
2. 改变MySQL的自动提交模式
SET SESSION / GLOBAL autocommit=0; 禁止自动提交 SET SESSION / GLOBAL autocommit=1; 开启自动提交
SET GLOBAL autocommit=0;
SHOW GLOBAL VARIABLES LIKE 'autocommit';
关闭了SQL当中全局的事务默认提交。
3. 实现事务 使用BEGIN, ROLLBACK, COMMIT 来实现
BEGIN; / START TRANSACTION; 开始一个事务 SQL操作语言; ROLLBACK; #事务回滚 COMMIT; #事务确认
BEGIN;
INSERT INTO student(NAME) VALUES ('Jim');
ROLLBACK;
COMMIT;
确认事务后,就不能在对事务里的操作语言进行回滚了。
再举一列:
BEGIN;
INSERT INTO student(NAME) VALUES ('Tom');
COMMIT;
ROLLBACK;
很明显对这条语句是没有进行回滚的,因为ROLLBACK是在COMMIT语句之后的。确认事务后就要遵从事务的特性了。
事务的隔离级别
在MySQL当中,只有InnoDB是支持事务的,所以在这里所所说的事务隔离级别是指InnoDB下的事务隔离级别。
查看当前的隔离级别
SELECT @@global.transaction_isolation,@@transaction_isolation;
设置隔离级别。
SET SESSION/GLOBAL TRANSACTION ISOLATION LEVEL 隔离级别;
- 读未提交(read uncommitted)(几乎不用)
一个事务可以读取到另一个事务未提交的修改。 这会带来脏读、幻读,不可重复读问题。 - 读已提交(read committed)
一个事务只能读取另一个事务已经提交的修改。 其避免了脏读。 但仍然存在不可重复读和幻读问题。 - 可重复读(repeatable read)(MySQL中的默认隔离级别)
同一个事务中多次读取相同的数据返回的结果是一样的,避免了脏读和不可重复读问题。(在MySQL8的InnoDB之前存在幻读情况,在8之后也没有了幻读情况) - 串行化(serializable)(性能最低)
事务串行执行,避免了以上所有问题。一次只能允许一个事务进行操作。 是最安全的,但效率是最低的。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|
未提交读(Read Uncommitted) | 可能 | 可能 | 可能 | 已提交读(Read Committed) | 不可能 | 可能 | 可能 | 可重复读(Repeatable Read) | 不可能 | 不可能 | InnoDB引擎不可能 | 串行化(Serializable) | 不可能 | 不可能 | 不可能 |
|