文章目录
- 1 最近打算
- 2 事务的基本特性
- 3 事务的隔离级别
1 最近打算
最近在研究spring事务的源码,因为spring事务的核心流程其实和spring-aop的核心流程很像,所以本想趁热打铁直接写几篇文章总结一下spring事务的核心流程的。但是今天下午突然想到之前在学校里为了考试,自己背诵事务的基本特性、事务隔离级别的时光。。。想到当时为了能拿满分,硬是非要按照当时的讲义一字不错的背下来的执着。。。想到当时在学校里其实学了那么多东西,但是却都留在了当时。。。
于是我决定这次从事务的基本特性+事务的隔离级别开始,先好好的整理一下事务的基础知识,就算这次整理完,之后随着时间的推移这部分内容又会在我的记忆里慢慢逝去,但我相信只要再次来到这里,我肯定会很快地就可将这部分内容重新拾起。
2 事务的基本特性
事务存在的意义是为了保证即使在并发情况下也能正确的执行crud操作。怎样才算是正确的呢?这时提出了事务需要保证的四个特性即ACID:
- A:原子性(atomicity)
指的是事务中各项操作,要么全部成功,要么全部失败; - C :一致性(consistency)
事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性保持稳定。 — 记得很清楚当时有个同学说就是“能量守恒定律”
,即我给你转了100块钱,我这里肯定少了100块,你那里肯定也只能多了100块。 - I :隔离性(isolation)
并发执行的事务彼此无法看到对方的中间状态; - D:持久性(durability)
事务完成后所做的改动都会被持久化,即使发生灾难性的故障 —> 通过日志和同步备份可以在故障发生后重建数据。
事务的ACID特性是由关系数据库系统(DBMS)来实现的,DBMS采用日志来保证事务的原子性、一致性和持久性。 日志记录了事务对数据库所作的更新,如果某个事务在执行过程中发生错误,就可以根据日志撤销事务对数据库已做的更新,使得数据库回滚到执行事务前的初始状态。
对于事务的隔离性,DBMS是采用锁机制来实现的。 即当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。
在高并发的情况下,要完全保证其ACID特性是非常困难的,除非把所有的事务串行化执行
,但带来的负面影响将是性能大打折扣。所以数据库中针对隔离性设计了四种隔离级别,供用户基于业务进行选择。
3 事务的隔离级别
事务的隔离级别主要有四个,即读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复度(Repeatable Read)和串行化(Serializable)。它们可能出现的问题如下:
接下来解释一下脏读、不可重复度和幻读。
-
脏读
A事务读到了B事务未提交的数据,就是所谓的脏读。 -
不可重复读
在同一个事务内的两个时间点读取同一个数据,读取到了不同的值,即发生了不可重复度。
更具体点的解释
:A事务在时间点t1读到了某数据的数值为data1, 在A事务未结束时,事务B更新了该数据的数值,假设更新为data2,并在时间点t2提交了事务, 事务A在时间点t2之后再次读该数据,发现此时数据变为data2了,而不是之前的data1了。 -
幻读
由于mysql的默认隔离级别为可重复读,因此不会出现脏读和不可重复读,因此如果当数据库使用的是mysql的话,最容易出现的就是幻读。那什么是幻读呢?用如下两个栗子来说明。- 栗子①: A事务在时间点t1读到了数据D的数值为1000, 在A事务未结束时,事务B更新了该数据的数值,假设更新为1100,并在时间点t2提交了事务,事务A在时间点t2之后再次读该数据 —> 这时候该数据肯定仍为1000(如果为1100就为不可重复读了),但是事务A在时间点t2之后,对该数据做了一次D = D+100的操作,之后再去查询数据D时,发现结果却为1200 —>按理说事务A刚刚在时间点t2之后还查到数据D的值为1000,仅仅对数据D做了一次D = D+100的操作,结果却成了1200,好像事务A刚才在时间点t2之后看错了,出现了幻觉一样 —> 即出现了幻读。
- 栗子②: 事务A要对当前的所有员工都发1000块钱的奖金,于是先查了一下所有的员工数据,发现工资表里有小王、小李、小赵三个人,于是打算做一次更新工资的操作update t_salary set salary = salary + 1000;,但是在事务A进行更新操作之前,事务B在数据库里插入里一条数据小马,并提交了事务。之后事务A开始进行更新操作,按说它刚刚看到只有三人,但是更新操作却显示更新了4条记录,而且查表一看果然有四条数据,可是刚刚明明看到的是三条数据啊,怎么又成四条了,好像出现了幻觉一样 —> 即出现了幻读。
通过上面两个栗子,可以总结一下出现幻读的场景:A事务和B事务同时操作一份数据D,假设B事务对数据D进行了修改并进行了提交,事务A再对数据D进行操作,在操作之前事务A看到的数据D仍然是B事务修改之前的数据,但当事务A对数据D进行修改时,却是对事务B修改后的数据进行修改。