前文回顾:多表查询
[2.1 准备数据表:](#2.1 准备数据表:)
[2.2 演示转账操作](#2.2 演示转账操作)
[2.3 演示在中间出现异常的情况并引出事务](#2.3 演示在中间出现异常的情况并引出事务)
[2.3.1 设置手动提交事务 / 回滚](#2.3.1 设置手动提交事务 / 回滚)
[2.3.2 不修改提交事务的方式,使用开启事务](#2.3.2 不修改提交事务的方式,使用开启事务)
[3. 事务的四大特性 ACID(面试题)](#3. 事务的四大特性 ACID(面试题))
[4. 并发事务引发的问题](#4. 并发事务引发的问题)
1.事务简介
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
案例:银行转账,如果转账过程中的操作有一步是抛出异常整个转账流程失败,让后事务回滚 恢复抛异常之前的操作。
默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。
2.事务操作
2.1 准备数据表:
sql
create table account(
id int auto_increment primary key comment '主键id',
name varchar(10) comment '姓名',
money int comment'余额'
)comment '账户表';
INSERT INTO account (id, NAME, money)
VALUES
(NULL, '张三', 2000),
(NULL, '李四', 2000)
select * from account;
-- 数据恢复,方便后面操作
update account set money = 2000 where name = '张三' or name = '李四';
2.2 演示转账操作
sql
-- 转账操作(张三转给李四1000)
-- 1、查询张三账户的余额
select * from account where name = '张三';
-- 2、将张三账户的余额-1000
update account
set money =
case
when money > 1000 then
money - 1000
else
money
end
where name = '张三';
-- 3、将李四账户的余额+1000
update account set money = money + 1000 where name = '李四';
2.3 演示在中间出现异常的情况并引出事务
上面 2.2 的代码是完全不会抛出异常的,因为我们要演示事务并引出事务的语法,所以我们在代码步骤三之前让程序抛出异常提前结束。执行观察出现的情况。
sql
-- 数据恢复,方便后面操作
update account set money = 2000 where name = '张三' or name = '李四';
-- 转账操作(张三转给李四1000)
-- 1、查询张三账户的余额
select * from account where name = '张三';
-- 2、将张三账户的余额-1000
update account
set money =
case
when money > 1000 then
money - 1000
else
money
end
where name = '张三';
程序抛出异常
-- 3、将李四账户的余额+1000
update account set money = money + 1000 where name = '李四';
选中上面的代码执行后发现抛出异常,数据表的结果如下:
分析:一开始"张三"和"李四"都有"两千元"的余额,将"张三"的 一千元 转账给"李四",结果"张三"的账户减去的 一千 但是"李四"并没有加上"张三"转的 一千,这显然是出现了bug。那么我们怎么解决这一问题。我们需要将转账操作整个流程控制 在一个事务中。
MySQL中的事务是默认提交。可以认为"一条语句就是一个自动提交的事务",但严格来说,是"每条语句被自动包装在一个事务中并立即提交"。
那么我们怎么来控制事务。这就需要使用下面我们学习到的语句来设置事务提交方式为手动提交。
2.3.1 设置手动提交事务 / 回滚
- 看 / 设置事务提交方式
SELECT @@autocommit; -- 查看事务提交方式
SET @@autocommit = 0;
- 提交事务
COMMIT;
- 回滚事务
ROLLBACK;
代码演示
sql
SELECT @@autocommit; -- 结果为1 代表当前事务自动提交
set @@autocommit = 0; -- 设置成手动提交
-- 转账操作(张三转给李四1000)
-- 1、查询张三账户的余额
select * from account where name = '张三';
-- 2、将张三账户的余额-1000
update account
set money =
case
when money > 1000 then
money - 1000
else
money
end
where name = '张三';
程序执行异常...
-- 3、将李四账户的余额+1000
update account set money = money + 1000 where name = '李四';
-- 提交事务
commit;
-- 回滚事务
rollback;
上面代码执行转账操作,如果抛出异常我们可以执行回滚事务 rollback 语句,则会将事务中所有未提交的更改撤销,恢复到事务开始前的状态(保证了数据库当中数据的正确性)。如果没有抛出异常可以执行提交事务 commit语句。
2.3.2 不修改提交事务的方式,使用开启事务
- 开启事务
START TRANSACTION 或 BEGIN;
- 提交事务
COMMIT;
- 回滚事务
ROLLBACK;
代码演示
sql
-- 方式2 不修改提交事务的方式
-- 转账操作(张三转给李四1000)
-- 开始事务
START TRANSACTION -- 或者
BEGIN
-- 1、查询张三账户的余额
select * from account where name = '张三';
-- 2、将张三账户的余额-1000
update account
set money =
case
when money > 1000 then
money - 1000
else
money
end
where name = '张三';
程序执行异常...
-- 3、将李四账户的余额+1000
update account set money = money + 1000 where name = '李四';
-- 提交事务
commit;
-- 回滚事务
rollback;
3. 事务的四大特性 ACID(面试题)
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
- 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并外部并发操作影响的独立环境下运行。
- 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
4. 并发事务引发的问题
- 是指 A 事务和 B事务(或者多个事务)同时操作同一个数据库或者同一张表所引发的问题。
|-------|-------------------------------------------------------|
| 问题 | 描述 |
| 脏读 | 一个事务读到另一个事务还没有提交的数据 |
| 不可重复读 | 一个事务先后读取同一条记录,但是两次读取数据不同,称为不可重复读。 |
| 幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据的,又发现这行数据已经存在,好像出现了"幻影" |





