(六)、事务
1.事务简介
事务 是一组操作的集合,他是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即浙西操作要么同时成功,要么同时失败。
drop table if exists 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);
注意:
默认MySQL的事务是自动提交的,也就是说,当执行完一条DML语句时,MySQL会立即隐式的提交事务。
2.事务操作
(1).未出现异常下的事务
张三转账给李四
-- 事务 (张三给李四转账1000) -- 1.查询张三账户余额 select *from account where name='张三'; -- 2.将张三账户余额-1000 update account set account.money=account.money-1000 where account.`name`='张三'; -- 3.将李四的余额+1000 update account set account.money=account.money+1000 where account.`name`='李四';
(2).出现异常下的事务
当张三转完账单之后,李四账户还没来得及收时,有一个错误
-- 事务 (张三给李四转账1000) -- 1.查询张三账户余额 select *from account where name='张三'; -- 2.将张三账户余额-1000 update account set account.money=account.money-1000 where account.`name`='张三'; -- 3.将李四的余额+1000 圣诞树上的 -- 制造错误 update account set account.money=account.money+1000 where account.`name`='李四';
3.事务控制 - (第一种方法)
(1).事务管理方法
1.查看/设置事务提交方式
select @@autocommit; #如果为1就是自动提交,如果为0就是不自动提交 set @@autocommit=0; #设置事务不自动提交。
2.设置完手动提交后,我们要进行手动提交
commit; #事务提交
3.假如提交后出现了异常,我们可以执行这个语句进行回滚事务。
rollback; #事务回滚
(2).事务提交示列
- 事务控制 - 手动提交(但是未提交)
-- 事务 (张三给李四转账1000) select @@autocommit; set @@autocommit=0; -- 1.查询张三账户余额 select *from account where name='张三'; -- 2.将张三账户余额-1000 update account set account.money=account.money-1000 where account.`name`='张三'; -- 3.将李四的余额+1000 update account set account.money=account.money+1000 where account.`name`='李四';
- 事务控制 - 手动提交(进行提交)
单独 执行commit之后,以前编写的数据才会开始同步。
commit; • 1
(3).事务回滚示列
- 执行有异常代码未回滚但已提交
-- 事务 (张三给李四转账1000) select @@autocommit; set @@autocommit=0; -- 1.查询张三账户余额 select *from account where name='张三'; -- 2.将张三账户余额-1000 update account set account.money=account.money-1000 where account.`name`='张三'; -- 3.将李四的余额+1000 项目出现异常 update account set account.money=account.money+1000 where account.`name`='李四'; commit;
- 执行有异常代码回滚且已提交
rollback;
在提交之后执行回滚的话,数据并不会回滚。假如进行回滚的话,那么就不要执行提交了;如果执行提交的话,就不用执行回滚了。
rollback; #先回滚后提交 • 1
4.事务控制 -(第二种方法)
第二种方式我们不需要设置成手动提交。
(1).事务方法
1.开启事务
start transaction 或 begin;
2. 提交事务
commit;
3.回滚事务
rollback;
(2).事务控制
-- 2. 方法 start transaction -- 1.查询张三账户余额 select *from account where name='张三'; -- 2.将张三账户余额-1000 update account set account.money=account.money-1000 where account.`name`='张三'; -- 3.将李四的余额+1000 项目出现异常 update account set account.money=account.money+1000 where account.`name`='李四'; rollback; #假如有错我们就进行回滚的操作 catch commit; #假如运行没有异常进行提交的操作
5.事务四大特性 (ACID)
(1).四大特性
- 原子性: 事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性:事务完成时,必须使用所有的数据都保持一致状态。
- 隔离性:数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性:事务一旦提交或回滚,他对数据库中的数据的改变就是永久的。
6.并发事务问题
(1).并发事务引起的三大问题
脏读
: 一个事务读到另外一个事务还没有提交的数据。不可重复读
: 一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。幻读
:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了幻影。
(2).三大问题详细介绍
1.脏读:(读取为提交的修改事务,且执行一次查询)
张三开启一个取钱的事务,已经从卡中取了1000,余额还剩1000,但是未关闭服务(也就是还未执行提交)。 这个时候张三老婆同时也开启了一个查询的事务,此时张三老婆查看余额已经读取到了余额1000元。
2.不可重复读: (读取了提交的修改事务,且执行两次查询)
张三老婆正在查询银行卡余额发现有2000元,此时张三开启一个取钱的事务,从卡中取了1000 并提交了事务, 张三老婆再次查找余额,发现余额突然剩下1000了,于是急忙地找工作人员进行处理这个问题。
3.幻读:(读取了提交的新增事务,且执行了一次查询和一次新增)
张三开启事务在办理一个员工的入职手续,由于工作习惯张三 先查询了一下这个员工是否办理过入职,发现没有 便去上个厕所了,但此时另一个同事把这个员工添加了进去并提交了事务,张三上完厕所回来便添加这个员工 发现提示这个员工已经存在,便再次查询了这个员工,发现依然没有。张三 大叫见鬼了!!!!!
7.事务隔离级别
(1).事务隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 |
Read uncommitted | ✅ | ✅ | ✅ |
Read committed | ❌ | ✅ | ✅ |
Repeatable Read(默认) | ❌ | ❌ | ✅ |
Serializable | ❌ | ❌ | ❌ |
(2).查看/操作事务隔离级别
1.查看事务隔离级别
select @@transaction_isolation #版本6.0+ select @@tx_isolation #版本6.0一下
2.设置事务隔离级别
# 假如是session只对当前窗口有效,假如设置的是global那么全部窗口都有效 set [session|global] transaction isolation level {Read uncommitted | Read committed | Repeatable Read | Serializable } • 1 • 2
3.版本6.0一下用 select @@transaction_isolation 报错
(3).演示脏读
# global 全局都设置,session 设置当前窗口(会话) set global transaction isolation level Read uncommitted;
select @@tx_isolation;
结果读取到了未提交的数据
(4).演示不可重复读
(5).演示幻读