ACID概述
发布日期:2021-06-29 13:15:38 浏览次数:2 分类:技术文章

本文共 2328 字,大约阅读时间需要 7 分钟。

事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性;(附加知识,redis中的事务不具有原子性)

ACID属性:

原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要不就是全部都不执行。

一致性(Consistent):数据都必须保持一致状态。这就是说所有相关的数据规则都是必须应用于事务的修改,这样才能保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或者双向链表)也都是必须是正确的。

隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受到外部并发操作的影响的“隔绝独立”的环境下执行sql。也就是说,在不同的进程间,事务是不可见的。

持久性(Durable):事务完成之后,对于数据的修改是永久有效的,会实现磁盘上的数据改动。

 

 

说到事务,就先说说并发问题;

1.更新丢失:也就是两个事务交叉存在,两个事务最后顺序提交,然后事务A提交,再事务B提交,最后的结果就是事务B的改动,那么事务A的改动就丢失了。

2.脏读:两个事务交叉存在,事务A去修改某条数据,事务B去读取到了事务A修改后的数据,然后事务A发生了回滚操作,这个时候事务B所持有的数据就是一条脏数据,数据库不存在的数据。

3.不可重复读:两个事务交叉存在,事务A读取到了某条数据,然后事务B去修改某条数据,然后事务B提交了,这个时候事务A再去读取这条数据,结果不一致了。

4.幻读:两个事务交叉存在,比如事务A去修改某条数据,然后事务B新增了一条数据,然后事务B也提交了,这个时候,事务A发现数据库中又出现了一条没有修改过的数据,这结果发现不一致了。

总结而言:不可重复读和幻读都可以理解为出现了幻觉,其中一个人在修改,其中一个人在读取,读取的人两次读取对比,发现都不一致,就是不可重复读;那么幻读就是其中一个人在新增,一个人在读取;

那么说到这里,如果同学们真的思考了这两种幻觉读取的区别,我们可以发现,要想解决幻读这种,我们无法做到行锁,因为倘若的不可重复读这种并发问题,我们还可以在事务A在读取这条数据的时候,增加行读锁(共享锁),这样,在事务A还没结束之前,是没人可以修改这条数据的。但是对于幻读,幻读和不可重复读的区别就是一个是新增,一个是修改。修改是在原有数据的基础上修改,我们可以对其上锁,那么新增就管不了了,如果非要解决,就得上升到表级别锁了。在事务A修改的时间,对整张表进行上锁,这样,事务B就没法新增了。

 

那么此处需要引申一下 数据库的隔离级别

数据库隔离级别 读数据一致性 脏读 不可重复读 幻读
读未提交(Read uncommitted) 只保证不读取物理上损坏的数据
读已提交(Read Committed) 语句级别 ×
可重复读(Repeatable Read) 事务级别 × ×
串行化、序列化(Serializable) 事务级别 × × ×

 

 

上述表格中简单罗列了一下四种数据库隔离级别,那么四种隔离级别都对应了将会产生什么并发问题,将不可避免。

未提交读:也就是说,当如果两个事务之间对同一条数据进行操作,事务A可以读取到事务B执行的sql结果,但是事务B还没提交,事务A都可以读取到。

已提交读:也就是两个事务间同时执行,事务A只能读取到事务B提交后的数据,这个时候,存在这个情况,就是事务A读取到事务B提交后的结果,发现,诶,怎么数据变了?那么不可重复读和幻读是不能解决的。

可重复读:两个事务同时执行,事务A还未提交,这个时候发起事务B,做出了修改(自减-2)并提交,事务A再查询数据,和之前数据一致,事务A对某条数据进行自增+1,那么这时候,事务A提交,由于可重复读隔离级别下,使用了mvcc机制,采用执行的日志版本号,对数据进行修改,最终事务A提交的结果后,  数据在最初的基础上 -1;

串行化:两个事务同时进行,其不允许同时开启事务,也就是表级别锁,当事务A开始事务,事务B所有操作都是阻塞状态,只能等待事务A将所有操作执行完成后,解除表锁,那么这个时候,事务B才能进行操作。

 

对于上述的几种并发环境下,产生的事务问题,在之前的帖子中,有写过一篇 摆地摊买橘子的案例,有兴趣可以去翻翻我帖子。

 

最后再说一句,在现有的mysql版本中,缺省状态下的隔离级别为不可重复读。并没有解决幻读的情况,也就是说,现在互联网项目的业务情况,并不会严格要求幻读的杜绝,比如,我们一个请求批量通过所有评论数据,这个时候,又有人评论了一条新数据,那我们等到下次操作的时候再通过所有评论数据就可以了,并不会影响整个用户操作的流程。

对于上述的4中隔离级别,随着隔离级别的升级,那么虽然会对并发问题有有效的控制,但是整个数据库系统的吞吐性能将会下降。

在可重复读的隔离级别中,如果检索条件存在索引,我们将会默认对该条数据进行加锁,但是如果没有索引,那么就惨了,那么操作上,会对整个表进行上锁,那么将自动升级为类似串行化的隔离级别,那么这个时候,我们的数据库表性能将下降,所以说,索引必须设计合理,不然会数据的读写性能,不仅会影响当前进程的读写,还会影响其他进程的读写,这也是一个到时候出现了慢查询的问题,最不好定位的问题了:如果进程A被进程B锁住了整张表,隔离级别还是可重复读,进程A所涉及的sql都有最优索引,但还是出现了慢查询问题,这个时候程序员就懵逼了。哈哈。所以说,这里需要提到一句,当在某个好久未进行更新的模块,突然出现了问题,可能是由于其他脚本对其产生了影响,也有可能其他数据库占用了IO。后面在写篇文章再细细聊下间隙锁。

转载地址:https://changemax.blog.csdn.net/article/details/113095185 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:mysql 锁机制
下一篇:mysql为什么需要优化

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月15日 23时19分57秒