前言
在MySQL数据库中,事务(Transaction)是指一组SQL语句的执行序列,这些SQL语句要么全部执行成功,要么全部执行失败,保证数据库的一致性和完整性;用于操作量大、复杂度高的数据。
目录
一、事务介绍
1. 概念
2. 事务的ACID特点
二、事务间的干扰
1. 脏读
2. 不可重复读
3. 幻读
4. 丢失更新
三、事务的隔离级别
1. 读未提交(read uncommitted)
2. 读已提交(read committed)
3. 可重复读(repeatable read)
4. 串行化(serializable)
四、事务隔离级别作用范围
1. 查询全局事务隔离级别
2. 查询会话事务隔离级别
3. 设置全局事务隔离级别
4. 设置会话事务隔离级别
五、事务控制语句
1. 控制语句
2. 事务配置一般格式
3. 示例
3.1 提交事务
3.2 回滚事务
3.3 多点回滚
3.4 使用 set 设置控制事务
一、事务介绍
1. 概念
- 事务是一种机制、一个操作序列,包含了一组数据库操作命令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求
- 事务是一个不可分割的工作逻辑单元,执行并发操作时,事务是最小的控制单元。
- 适用于多用户同时操作的数据库系统的场景
- 通过事务的整体性以保证数据的一致性
2. 事务的ACID特点
事务的ACID是指数据库事务应该具备的四个特性,分别是原子性(Atomicity)、一致性(Consistency)、隔离性。这四个特性共同构成了事务的ACID属性,保证了数据库事务的可靠性、稳定性和一致性。
① 原子性:指事务是一个不可再分割的工作单位,事务中的操作要么都发生,要么都不发生。(如果事务中的任何元素失败,则整个事务将失败)
② 一致性:指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。(如:转账100给对方,对方余额多100,自己余额少100)
③ 隔离性:指在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。(当多人操作一张表时,只要不提交,数据会保持隔离互不干预;当有提交后,其他未参与的用户就可以看到新增的数据)
④ 持续性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。(一旦事务提交,处理记过都是永久保存在磁盘里)
二、事务间的干扰
1. 脏读
读取未提交的数据,意味着这些数据并不是最终保留到数据库的数据,可能会回滚;事务读取的数据就是脏数据。即一个事务读取了另一个事务正在修改但尚未提交的数据。
如图:事务B读取了事务A修改却没有提交的数据,此时得到的数据就是脏数据。事务B读取发生的情况称为脏读。
2. 不可重复读
前后多次读取,数据内容不一致。指在同一个事务中,如果读取同一行数据两次,可能会得到不同的结果。即一个事务内两个相同的查询却返回了不同数据,这是由于其他事务在读取过程中修改并提交了数据造成的。
如图:由于事务A在事务B两次读取之间做了修改并提交,导致事务B第一次读取到的数据和第二次读取到的数据内容不一致,从而形成了不可重复读。
3. 幻读
前后多次读取,数据总量不一致。指在一个事务中,由于其他事务插入新数据导致同一个查询条件返回不同数量的行的现象。通常发生在读取某个范围内的数据时,其他事务在该范围内插入新数据,导致第一次读取和第二次读取返回的行数不一致。即事务前后两次读取同一范围(这里的范围指行区间)的数据,后一次读取的总数(行)和前一次不一致称为幻读。
如图:由于事务A在事务B两次读取之间做了插入并提交,导致事务B第一次读取到的数据和第二次读取到的数据数量不一致,从而形成了不可重复读。
4. 丢失更新
两个事务同时读取一条记录。指两个事务同时读取同一行数据,并且在稍后更新同一行数据时,其中一个事务的更新操作覆盖了另一个事务的更新,导致后一个事务的更新丢失,从而造成数据不一致的情况。即后一个事务的更新覆盖了前一个事务的更新。
如图:事务A先修改,接着事务B也做修改;在事务B修改过程中,事务A先提交了,然后事务B接着提交。最终事务B提交的数据覆盖了A的数据结果,造成丢失更新。举个例子:银行卡内余额100元,A和B同时向银行卡转账100元,A先转入、B后转入,最终B得到余额1200元。
三、事务的隔离级别
1. 读未提交(read uncommitted)
读取尚未提交的数据,不解决脏读、允许脏读;即使其他事务未提交,本事务也能看到修改后的数据值。安全性最差,但性能最好。(不使用)
2. 读已提交(read committed)
读取已提交的数据,可以解决脏读,Oracle等多数数据库默认都是该级别。安全性较差,性能较好。(不重复读)
3. 可重复读(repeatable read)
重复读取可以解决脏读和不可重复读,mysql默认的可重复读。无论其他事务是否修改并提交了数据,在这个事务中看到的数据值始终不受其他事务影响。安全性较高,性能较差。
4. 串行化(serializable)
可以解决脏读、不可重复读和虚读——相当于锁表完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。安全性高,性能差。(不使用)
串行化事务隔离级别就像是在数据库中排起了队,每个人都要一个一个地走到柜台前办事。这种情况下,每次只有一个人可以进行操作,其他人需要等待。这样做可以确保每个人看到的信息都是最新的,不会出现信息不一致的情况。但是办事效率会变得很低,因为大家得排队等着办事,不能同时进行。
注意:mysql 默认的事务处理级别是 repeatable read ,而 Oracle 和 SQL Server 是 read committed 。
四、事务隔离级别作用范围
通过控制事务隔离级别,数据库管理系统可以灵活地调整事务之间的交互方式,从而平衡数据的一致性和并发性能。不同的隔离级别在读取和写入数据时的影响范围不同,其作用范围分为全局级和会话级。
1. 查询全局事务隔离级别
show global variables like '%isolation%';
select @@global.tx_isolation;
示例:
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
2. 查询会话事务隔离级别
show session variables like '%isolation%';
select @@session.tx_isolation;
select @@tx_isolation;
示例:
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
3. 设置全局事务隔离级别
set global transaction isolation level 隔离级别;
示例:
mysql> set global transaction isolation level read committed; # 修改全局会话级别
mysql> select @@global.tx_isolation; # 查询全局事务隔离级别
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| READ-COMMITTED | # 读已提交
+-----------------------+mysql> select @@tx_isolation; # 查询当前会话事务隔离级别
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ | # 可重复读
+-----------------+
# 注意:设置全局隔离级别会影响新建立的会话的默认隔离级别,但不会立即改变已经存在的会话的隔离级别
4. 设置会话事务隔离级别
set session transaction isolation level 隔离级别;
五、事务控制语句
在MySQL中,可以使用以下事务控制语句来管理事务的开始、提交、回滚等操作。
1. 控制语句
begin 或 start transaction
# 显式地开启一个事务。
commit 或 commit work
# 提交事务,并使已对数据库进行的所有修改变为永久性的。
rollback 或 rollback work
# 回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。
savepoint S1:
# 使用 savepoint 允许在事务中创建一个回滚点,一个事务中可以有多个 savepoint;“S1”代表回滚点名称。
rollback to [savepoint] S1
# 把事务回滚到标记点。
2. 事务配置一般格式
use 库名;
begin;
动作 表名 set 字段 = 表达式;
select * from 表名; # 观察两个事务数据差异
commit;
3. 示例
准备表:
mysql> create database school;
mysql> use school;
mysql> create table class01 (id int(5) not null primary key,name varchar(40),money double);
# money double的意思是在MySQL数据库表中创建一个名为money的列,该列的数据类型为双精度浮点数,用于存储货币金额或其他需要高精度的数值数据。
mysql> insert into class01 values(1,'zhangsan',1000);
mysql> insert into class01 values(2,'lisi',1000);
mysql> select * from class01;
+----+----------+-------+
| id | name | money |
+----+----------+-------+
| 1 | zhangsan | 1000 |
| 2 | lisi | 1000 |
+----+----------+-------+
3.1 提交事务
① 开启事务
mysql> begin;
mysql> update class01 set money = money - 100 where name='zhangsan';
此时未提交事务,另打开新的终端查看表信息,对比结果:
此时事务A如果退出,修改的操作就被丢弃 。
② 提交事务
提交事务后,所有用户再次查询将看到最新的数据。
3.2 回滚事务
① 更新数据
mysql> begin;
mysql> update class01 set money = money + 100 where id=2;
mysql> select * from class01;
+----+----------+-------+
| id | name | money |
+----+----------+-------+
| 1 | zhangsan | 900 |
| 2 | lisi | 1100 |
+----+----------+-------+
② 回滚事务
mysql> rollback;
mysql> select * from class01;
+----+----------+-------+
| id | name | money |
+----+----------+-------+
| 1 | zhangsan | 900 |
| 2 | lisi | 1000 |
+----+----------+-------+
3.3 多点回滚
① 更新数据,设置回滚点
mysql> begin;
mysql> update class01 set money = money + 100 where id=1;
mysql> select * from class01;
+----+----------+-------+
| id | name | money |
+----+----------+-------+
| 1 | zhangsan | 1000 |
| 2 | lisi | 1000 |
+----+----------+-------+
mysql> savepoint S1; #设置回滚点S1mysql> update class01 set money = money + 100 where id=2;
mysql> select * from class01;
+----+----------+-------+
| id | name | money |
+----+----------+-------+
| 1 | zhangsan | 1000 |
| 2 | lisi | 1100 |
+----+----------+-------+
mysql> savepoint S2; #设置回滚点S2mysql> insert into class01 values(3,'wanger',2000);
mysql> select * from class01;
+----+----------+-------+
| id | name | money |
+----+----------+-------+
| 1 | zhangsan | 1000 |
| 2 | lisi | 1100 |
| 3 | wanger | 2000 |
+----+----------+-------+
② 回滚S1
mysql> rollback to S1; #回滚至S1
mysql> select * from class01;
+----+----------+-------+
| id | name | money |
+----+----------+-------+
| 1 | zhangsan | 1000 |
| 2 | lisi | 1000 |
+----+----------+-------+
3.4 使用 set 设置控制事务
set autocommit=0;
#禁止自动提交
set autocommit=1;
#开启自动提交,mysql默认为1
show variables like 'autocommit';
#查看Mysql中的autocommit值示例:
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON | #默认开启自动提交
+---------------+-------+
mysql> set autocommit=0;
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | OFF | #已禁止自动提交
+---------------+-------+