MYSQL事务及ACID数据

事务及ACID数据

事务是一组操作要么全部成功,要么全部失败,目的是保证数据最终的一致性。

事务具有以下四种属性,通常简称为事务的ACID属性。

  1. 原子性(Atomicity):当前事务的操作要么同时成功,要么同时失败,原子性由undo log日志实现
  2. 一致性(Consistent):使用事务的最终目的,由其他三个特性以及业务代码正确逻辑来实现。
  3. 隔离性(Isolation):在事务并发执行时,他们内部的操作不能互相干扰。隔离性由Mysql的各种锁及MVCC机制来实现。
  4. 持久性(Durable):一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由redo log日志来实现。

并发事务处理带来的问题

更新丢失(Lost Update)或脏写

当两个或者多个事务同时对一行数据进行修改,有可能发生丢失问题,即最后的更新覆盖了由其他事务所做的更新。

脏读(Dirty Reads)

事务A读取到事务B已经修改但为提交的数据

不可重复读(Non-Repeatable Reads)

事务A在内部的相同查询语句在不同时刻查询出来的结果不一致

幻读(Phantom Reads)

事务A读取到了事务B提交的新增数据

事务隔离级别

隔离界别脏读不可重复读幻读
读未提交(Read Uncommitted)可能可能可能
读已提交(Read Committed)不可能可能可能
可重复读(Reaetable Read)不可能不可能可能
串行化(Serializable)不可能不可能不可能

查看当前数据库的事务隔离级别: show variables like ‘tx_isolation’;

设置事务隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET tx_isolation = ‘REPEATABLE-READ’;

Mysql默认的事务隔离级别是可重复读。

事务隔离级别案例分析

读未提交:

account 表添加三条数据
在这里插入图片描述
事务1

# 设置事务级别为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
# 查询表数据
BEGIN;
select * from account;

数据结果:
在这里插入图片描述

此时存在另外一个事务2

# 设置隔离级别为读未提交并且更新account.blance数据
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

BEGIN;
update account set balance = balance - 50 where id = 1;
select * from account;

# 执行回滚操作
# ROLLBACK;

此时事务2查询到的数据已经更新,且事务1查询的结果也是如此
在这里插入图片描述
当事务1拿到这个数据结果并执行逻辑运算的时候时候,事务2由于某种原因并未提交事务而是进行了ROLLBACK回滚事务操作,那么事务1拿到的数据将会是脏数据

不可重复读

事务1

# 设置事务为读已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

BEGIN;
select * from account;

commit;

事务2

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

BEGIN;
update account set balance = balance - 50 where id = 1;
select * from account;

# 未提交
# COMMIT;

事务2查询结果:
在这里插入图片描述
此时事务1查询结果为:
已经解决了脏读问题
在这里插入图片描述
事务1

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

BEGIN;
# 事务2未提交前进行查询,结果为450
select * from account;

# 事务2提交后进行查询,结果为400
select * from account;

commit;

存在不可重复读的问题

可重复读

事务1

SET tx_isolation = 'REPEATABLE-READ';
BEGIN;
select * from account ;
commit;

先执行查询:
在这里插入图片描述

事务2

set tx_isolation = 'repeatable-read';

BEGIN;
update account set balance = balance - 50 where id = 1;
select * from account;
COMMIT;

执行结果:
在这里插入图片描述

此时在事务1中只执行查询语句发现结果仍没有变化,解决了不可重复读的问题:
在事务2中执行插入语句

set tx_isolation = 'repeatable-read';

BEGIN;
update account set balance = balance - 50 where id = 1;

insert account (id, name ,balance) VALUES (4, 'zhangsan', '5000');
select * from account;
COMMIT;

在执行事务1的时候,结果如下:
在这里插入图片描述
同时在其他事务中执行整个库中其他表的数据的时候,在事务1中查询的仍是在最开始执行查询一瞬间数据的快照(历史版本);
insert、update和delete是读当前版本,且update时会对操作行添加一个行锁

幻读验证

事务1中查询数据:
在这里插入图片描述
此时在事务2中新插入一条数据

set tx_isolation = 'repeatable-read';

BEGIN;

insert account (id, name ,balance) VALUES (4, 'zhangsan', '5000');
select * from account;
COMMIT;

执行结果:
在这里插入图片描述

此时事务1查询的时候数据仍为三条;
但是在事务1中直接对id=4的数据进行更新时,仍可以更新成功且再执行查询时可以查询得到;

update account set balance = balance - 500 where id = 4;

在这里插入图片描述
即幻读问题仍存在。

串行化

事务1

SET tx_isolation = 'SERIALIZABLE';
BEGIN;

select * from account where id = 1;

当事务1设置模式为Serializable时,事务2进行更新id = 1 的操作将会阻塞等待,但是更新id = 2 的操作仍可以成功,说明在串行化模式下innodb的查询也会被加上行锁。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值