这是我参与8月更文挑战的第7,活动详情查看:8月更文挑战
因最近遇到Spring事务管理相关问题,故总结记录一下问题
1 什么是事务
如果一个业务完成,需要执行多条SQL语句.即涉及多个增删改查.必须使用事务.简单来说,事务,就是把这些所有的SQL语句当做一个整体来执行,要么全部成功,要么全部失败. 如果执行失败,则需要回滚到没有执行SQL前的状态.
2 事务的四大特性
原子性,一致性,隔离性,持久性.
| 事务特性 | 含义 |
|---|---|
| 原子性(Atomicity) | 一个事务所有的SQL语句是一个整体,不可分割。要么全部成功,要么全部失败 |
| 一致性(Consistency) | 对数据库中数据的操作状态在事务执行前后必须是一致的, 如:转账前2个人的总金额与转账后2个人的总金额是一致的 |
| 隔离性(Isolation) | 每个表中同时有多个事务在执行,事务与事务之间是隔离的,不能相互影响 |
| 持久性(Durability) | 如果一个事务执行成功,对数据库的影响是持久的,服务器关闭也是存在的 |
3 事务的应用场景
1 银行转账业务模拟
虹猫给蓝兔转1000元,而这个业务,至少要执行2条语句,即虹猫扣减1000元语句,蓝兔增加1000元语句.
-- 创建账户表:id,name,balance
create table account(
id int primary key auto_increment, -- 主键自动增长
name varchar(20), -- 账户名
balance int -- 账户的余额
);
-- 添加数据:虹猫和蓝兔各1000块
insert into account values(null, 'hm',2000),(null,'lt',2000);
select * from account;
-- 模拟虹猫转账给蓝兔 1000块钱的功能:
-- 至少要执行2条SQL语句
-- 1. 更新虹猫账户,虹猫减1000
-- 2. 更新蓝兔账户,蓝兔加1000
-- 执行第1条
update account set balance=balance-1000 where name='hm';
-- 执行第2条,可能会出现第1条语句执行成功,第2条语句没有执行,或者执行失败的情况
update account set balance=balance+1000 where name='lt';
-- 查询转账后结果
select * from account;
-- 还原2个账户的钱为1000
update account set balance = 2000;
如果当虹猫扣减1000元的语句执行了,此时遭遇其他意外问题,服务器崩溃了.给蓝兔增加1000元的语句没有执行,那么数据就出了问题,对于银行类机构,这样问题不能容忍的.
所以,我们要保证,如果有一个语句出现问题,整个转账就算失败.数据恢复到没执行语句前的状态. 只有两个语句都成功了,这个转账就算成功.这就是事务的应用场景.
4 事务的提交
事务的提交,分为手动提交和自动提交.
默认情况下Mysql任务每条DML语句(增删改)都是一个单独的事务,所以上面转账的是2个事务在执行.
1 手动提交
手动提交事务,即通过人为控制事务的开启,关闭,回滚.
1 相关命令操作
| 功能 | SQL语句 |
|---|---|
| 开启事务 | start transaction |
| 提交事务 | commit |
| 回滚事务 | rollback |
2 手动提交事务
1 开启事务
2 执行业务相关的多条sql语句 (此时并没有把数据写到数据库表中,所有的操作都是在一个日志文件去完成)
3 如果所有的SQL语句都没有异常,提交事务
4 如果有失败的语句,则进行回滚事务
3 案列
1 提交事务
模拟虹猫给蓝兔转1000元成功的案列.
1 使用Dos控制台进入Mysql
2 执行业务流程
start transaction;
select * from account;
update account set balance=balance-1000 where name='hm';
update account set balance=balance+1000 where name='lt';
select * from account;
commit;
- 1开启事务
- 2 虹猫账号-1000
- 3 蓝兔账号+1000
- 4 使用navicat查看数据库,数据不变.
- 5 在控制台提交事务
- 6 使用navicat查看数据库,数据改变.
navicat事务提交前:
navicat事务提交后:
2 回滚事务
模拟虹猫给蓝兔转1000元失败的案列.
1 使用Dos控制台进入Mysql
2 执行业务流程
start transaction;
select * from account;
update account set balance=balance-1000 where name='hm';
update account set balance=balance+1000 where name='lt';
select * from account;
rollback;
select * from account;
- 1开启事务
- 2 虹猫账号-1000
- 3 蓝兔账号+1000
- 4 使用navicat查看数据库,数据不变.
- 5 在控制台回滚事务
- 6 使用navicat查看数据库,数据改变.
navicat事务提交前:
navicat事务提交后:
2 自动提交
自动提交的关闭和开启.
| 功能 | Sql语句 |
|---|---|
| 查看当前事务自动提交状态 | Select @@autocommit; |
| 改变事务状态0表示手动,1表示自动 | set @@autocommit=1; |
1 默认提交方式
Mysql默认情况下,认为每条DML语句(增删改)都是一个独立的事务,所以上面的案例,mysql认为是2个事务在执行.
每条语句开始执行前会自动开启事务,执行完毕会自动提交事务,这样我们就不能进行回滚了。
为了完成相关的业务, 我们必须要能有回滚的功能. 可通过设置Mysql的事务提交方式.默认是自动提交,我们可以手动关闭该功能.
2 案例
1 自动提交事务
select * from account;
update account set balance=balance-1000 where name='hm';
select * from account;
- 1 更新虹猫账户-1000
- 2 使用navicat查看数据
2 关闭自动提交事务
- 1 关闭自动提交事务
- 2 更新虹猫账户-1000
- 3 使用navicat查看数据
- 4 提交事务
- 5 使用navicat查看数据
- 6 开启自动提交事务
Select @@autocommit;
set @@autocommit=0;
update account set balance=balance-1000 where name='hm';
commit;
set @@autocommit=1;
navicat事务提交前:
navicat事务提交后:
3 事务的回滚
1 事务回滚的概述
事务回滚: 回滚到事务执行前最开始的状态.如果不愿意回滚到最开始的状态,可以回滚到整个流程中的一步.
提前保存回滚点,再回滚到保存的这个位置.
| 事务的操作 | MySQL操作事务的语句 |
|---|---|
| 开启事务 | start transaction |
| 提交事务 | commit |
| 回滚事务 | rollback |
| 设置回滚点 | savepoint 回滚名字 |
| 回到回滚点 | rollback to 回滚名字 |
| 查询事务的自动提交情况 | select @@autocommit |
| 设置事务的手动提交方式 | set @@autocommit |
2 回滚案例
1 案例步骤
- 1 开启事务
- 2 让虹猫的账号减500元
- 3 设置回滚点
- 4 让虹猫的账号减500元
- 5 回到回滚点
- 6 提交事务
start transaction;
select * from account;
update account set balance=balance-500 where name='hm';
savepoint back_point_one;
update account set balance=balance-500 where name='hm';
rollback to back_point_one;
commit;
select * from account;
navicat事务提交前:
navicat事务提交后: