文章目录
1. 事务简介2. 事务操作2.1 未控制事务2.2 控制事务2.2.1 查看事务的提交方式2.2.2 设置事务的提交方式2.2.3 提交事务2.2.4 回滚事务2.2.5 开启事务2.2.6 完善转账案例
3. 事务的四大特性(ACID)4. 并发事务引发的问题5. 事务隔离级别5.1 演示5.1.1 Read Uncommitted(RU)5.1.2 Read Committed(RC)5.1.3 Repeatable Read(RR)5.1.4 Serializable
5.2 查看隔离级别5.3 设置事务隔离级别
1. 事务简介
DBMS:Database Management System,数据库管理系统
事务(Transaction)是数据库管理系统(DBMS)中一个不可分割的工作单位,它由一系列操作组成,这些操作要么全部成功执行,要么全部失败回滚,不会处于中间状态
事务的主要目的是保证数据的一致性和完整性,常见的事务案例就是银行转账
我们先来看一下正常的银行转账业务
我们再来看一下转账异常的情况,如果张三取出钱后,再转账给李四的过程中业务出现了异常,会怎么样呢
如果业务出现了异常,张三的钱扣了,但是李四却没收到钱,出现了数据不一致的情况
那怎么解决呢,我们只需要把整个流程都放在一个事务里面,当所有操作都执行完成了之后,再提交事务
MySQL 的事务默认是自动提交的,也就是说,当执行一条 DML 语句时,MySQL 会立即隐式地提交事务
2. 事务操作
我们先准备一张名为 account 的表,表的结构和表数据如下
create table account
(
id int primary key AUTO_INCREMENT comment 'ID',
name varchar(10) comment '姓名',
money double(10, 2) comment '余额'
) comment '账户表';
insert into account(name, money)
VALUES ('张三', 2000),
('李四', 2000);
2.1 未控制事务
我们先来测试正常情况
-- 1.查询张三余额
select *
from account
where name = '张三';
-- 2.张三的余额减少1000
update account
set money = money - 1000
where name = '张三';
-- 3.李四的余额增加1000
update account
set money = money + 1000
where name = '李四';
测试完毕之后检查数据的状态, 可以看到数据操作前后是一致的
测试异常情况
我们先把数据都恢复到2000, 接着一次性执行以下 SQL 语句
-- 1.查询张三余额
select *
from account
where name = '张三';
-- 2.张三的余额减少1000
update account
set money = money - 1000
where name = '张三';
出错了....
-- 3.李四的余额增加1000
update account
set money = money + 1000
where name = '李四';
由于 出错了.... 这句话 不符合 SQL 语法,执行后会报错
检查最终的数据情况,发现数据在操作前后并不一致
2.2 控制事务
2.2.1 查看事务的提交方式
SELECT @@autocommit;
2.2.2 设置事务的提交方式
autocommit = 1 表示自动提交
SET @@autocommit = 0;
2.2.3 提交事务
commit;
2.2.4 回滚事务
rollback;
2.2.5 开启事务
start transaction;
2.2.6 完善转账案例
-- 开启事务
start transaction;
-- 1.查询张三余额
select *
from account
where name = '张三';
-- 2.张三的余额减少1000
update account
set money = money - 1000
where name = '张三';
-- 3.李四的余额增加1000
update account
set money = money + 1000
where name = '李四';
-- 如果正常执行完毕, 则提交事务
commit;
-- 如果执行过程中报错, 则回滚事务
rollback;
3. 事务的四大特性(ACID)
原子性(Atomicity): 原子性确保事务中的所有操作要么全部完成,要么全部不完成,不会出现部分完成的情况。事务中任何一个操作失败,整个事务将被回滚,就像事务从未执行过一样一致性(Consistency): 一致性确保事务执行的结果是数据库状态的合法状态,即数据库在事务开始和结束时的数据满足预定义的约束条件(如外键约束、唯一性约束等)隔离性(Isolation): 隔离性确保并发执行的事务彼此隔离,一个事务的中间状态不会被其他事务所见。这意味着即使在多个事务同时执行时,每个事务都感觉自己是唯一在执行的事务持久性(Durability): 持久性确保一旦事务提交,其结果就永久保存在数据库中。即使发生系统故障,如电源故障或系统崩溃,已提交事务的结果也不会丢失,持久性一般是通过将事务的输出写入到持久存储设备(如硬盘)来保证
4. 并发事务引发的问题
赃读:一个事务读到另外一个事务还没有提交的数据不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读幻读:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了"幻影"
脏读的示例(事务 A 中没提交的数据被事务 B 读取)
不可重复读的示例(事务 A 在第一步和第三步查询的 id 为 1 的数据不一致)
幻读的示例
事务 A 在第一步查询到 id 为 1 的数据不存在事务 A 在执行 insert 语句前,事务 B 提交了事务,往表中插入了 id 为 1 的数据事务 A 在第二步执行 insert 语句,执行失败,因为破坏了主键的唯一性事务 A 在第三步查询到 id 为 1 的数据仍然不存在
5. 事务隔离级别
为了解决并发事务所引发的问题,在数据库中引入了事务隔离级别,事务隔离级别主要有以下几种:
5.1 演示
我们来演示一下,在不同的隔离级别情况下,并发事务可能引发的问题
5.1.1 Read Uncommitted(RU)
脏读(一个事务读到了另一个事务还没有提交的数据)
5.1.2 Read Committed(RC)
Read Committed 隔离级别虽然解决了脏读问题,但是没有解决不可重复读的问题(一个事务先后读取同一条记录,但两次读取的数据不同)
5.1.3 Repeatable Read(RR)
Read Committed 隔离级别虽然解决了不可重复读问题,但是没有解决幻读的问题(一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了"幻影")
5.1.4 Serializable
Read Committed 隔离级别解决了所有并发事务引发的问题
5.2 查看隔离级别
查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
5.3 设置事务隔离级别
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
SESSION 设置的是当前会话(也就是当前连接)的隔离级别GLOBAL 设置的是全局隔离级别
事务隔离级别越高,数据越安全,但是性能越低
示例
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;