MySQL事务


MySQL事务

事务是一组操作的集合,这一组操作具有原子性,事务会保证这一组操作要么全部执行成功,要么全部失败,也就是如果事务的操作中有一步操作出现异常,事务执行失败会将所有操作进行回滚。

典型的使用场景就是转账操作,张三给李四转1000块钱,转账这个操作分为三步:

  • 先查询张三账户余额
  • 张三账户扣除1000块
  • 接着给李四账户加1000块

那么这两个操作要么同时执行成功,要么就都失败。

1. 事务四大特性(ACID)

  • 原子性(Atomicity):原子是不可分割的最小单元,而事务的原子性指的就是要么全部成功,要么全部失败
  • 一致性(Consistency):事务完成时,必须保证所有数据处于一致状态,比如说转账操作,张三和李四之间进行转账操作前他们的总余额为10000,转账操作后也必须是10000
  • 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境运行,也就是事务和事务并发操作具有隔离性
  • 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变时永久的

2. 操作事务

默认MySQL的事务是自动提交的,也就是说,当执行完一条语句时,MySQL会立即隐式的提交事务。通过start transaction开启事务,我们就可以手动提交和回滚事务了。

开启事务

start transaction;

提交事务

commit;

回滚事务

rollback

准备数据

 create table balance  
 (
  id int primary key auto_increment comment '用户id',  
  name varchar(16) comment '用户名',  
  money decimal(10,2) comment '账户余额'  
 );
insert into balance (name,money) values('张三',5000),('李四',5000);

测试事务回滚,在转账过程中如果发生异常就可以回滚事务,如果没有发生任何异常就可以直接提交事务。

模拟转账:

-- 开始事务
start transaction;
-- 查询账户余额
select * from balance;
+----+--------+---------+
| id | name   | money   |
+----+--------+---------+
|  1 | 张三   | 5000.00 |
|  2 | 李四   | 5000.00 |
+----+--------+---------+
-- 张三账户余额减少
update balance set money=money-1000 where name='张三';
-- 李四账户余额增加
mysql> update balance set money=money+1000 where name='李四';


-- 全部执行成功提交事务
commit;


-- 如果执行失败则回滚事务
-- rollback;

3. 并发事务问题

在并发场景下事务会出现以下问题:

  1. 脏读:一个事务读到另外一个事务还没有提交的数据,一般针对的是一条数据

    以张三给李四转账1000为例:

    • 假设张三账户里有5000块钱,张三转账这个操作先开启了事务A
    • 接着对张三账户的余额修改为4000,此时事务A还没有提交
    • 接着另外一个事务B又来查询张三的余额,查询完毕后此时张三的余额为4000
    • 同时给李四余额进行增加时发送了异常,此时整个事务A进行了回滚
    • 那么此时张三的账户余额还是5000,而另外一个事务B读取到的则是4000这个“脏数据”
  2. 不可重复读:一个事务先后读取同一条记录,当两次读取的数据不同,也是针对的一条数据

    • 假设事务A第一先去查询张三的账户余额,发现是5000
    • 而同时事务B把张三的余额修改成功了4000,同时提交了事务
    • 紧接着事务A又进行了一次查询,发现此时张三的账户余额为4000
  • 同一个事务两次查询同一份数据出现了不一样的结果这就是不可重复读
  1. 幻读:⼀个事务两次查询中得到的结果集不同,因为在两次查询中另⼀个事务有新增了⼀部分数据 ,好像出现"幻觉",而幻读一般是针对表级别的
    • 事务A去查询用户表中有没有有一个叫王五的用户,发现没有
    • 与此同时事务B往用户表里插入了一个叫王五的用户,并且提交了事务
    • 接着事务A也插入一个王五的用户,发现插入失败
    • 一个事务查询时发现这个数据不存在,而插入时这个数据又出现了,这就是幻读

4. 事务的隔离级别

隔离级别脏读不可重复读幻读
读未提交(Read uncommitted)存在存在存在
读已提交(Read committed)不存在存在存在
可重复读(Repeatable Read(默认))不存在不存在存在
串行化(Serializable)不存在不存在不存在

事务的隔离级别越高,数据越安全,但是性能也越低的

MySQL5.X查看隔离级别:

select @@global.tx_isolation;

设置事务隔离级别

SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

读未提交

-- 设置隔离级别为读未提交
set global transaction isolation level Read uncommitted;

测试脏读

此时的隔离级别为读未提交

在这里插入图片描述

读已提交

测试脏读

不存在脏读问题

在这里插入图片描述

不可重复读

显然读已提交存在不可重复读问题

在这里插入图片描述

可重复读

测试不可重复读问题,不存在该问题

在这里插入图片描述

串行化

测试幻读,发现B事务还没提交A事务同事插入了同一条数据,事务A直接阻塞了,所以不存在幻读问题

在这里插入图片描述


  • 28
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱敲代码的三毛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值