数据库-事务

数据库事务基本也是数据库基础的一部分,虽然编程的时候注意的地方比较少。但是面试问题是真的多,几乎是必中。
事务的作用大家都比较清楚,而且不只是数据库才有事务一说,分布式事务、redis事务也都有,所以事务是一种概念
但是难点都是在MySQL的事务实现原理,为了实现事务,MySQL都用什么来实现的。

事务的特性,与mysql的实现原理
A原子性:一个事务中的操作,要么都完成,要么都不做。
C一致性:事务保证数据的一致性,一个事务处理完成后数据保证一致且合法的(其实也都是相对的)。
I隔离性:两个事务同时操作互相不影响。
D持久性:事务做完的操作能够持久化保存。
实现原理:
持久性实现通过redolog。redolog记录了事务做了哪些操作,但是还没有刷新到数据库文件中的,即使是宕机等事故未进行数据文件的更新,也可以根据redolog日志进行更新数据库文件内容。
原子性实现通过undolog。如果事务确定需要完成使用redolog去刷新数据库文件,但是当数据库决定回滚事务的话,就会使用undolog,undolog记录事务中数据修改前的记录内容,需要回滚事务的时候使用undolog记录的内容恢复数据库文件内容即可。
隔离性实现是根据隔离级别的不同,而使用了不同的实现方式,在事务隔离界别中详细讲述实现原理。
一致性其实是一种数据库最终的状态,它是通过前面三个性质结合起来实现的,所以它没有单独的实现方法,因为前面三个特性实现了它就实现了(所以个人感觉一致性就是拿出凑数的一个性质啊)。

事务隔离级别问题理解三步走:
事务无隔离的情况下产生的问题
1.更新丢失:两个事务同时修改同一数据,一个事务覆盖另一个事务修改的数据。
2.脏读:两个事务AB同时运行,事务A修改数据,事务B读取了修改后的数据进行处理,事务A回滚而事务B仍然用修改的数据处理。
3.不可重复读:事务A读取数据,事务B对该数据进行修改,事务A再次读取该数据发现与原来的对不上了。
4.幻读:事务A根据条件查询数据行总共有10个,事务B增加了一个数据行,事务A再次查询数据行总共有11个。

事务的隔离级别实现原理
1.数据库锁,在 数据库-锁 一文中进行介绍。
2.多版本并发控制mvcc,它用在可重复读和读已提交这两个隔离级别下。实现原理是依靠记录行隐藏的事务id字段和rollback指针字段,和undolog记录的版本信息,还有readview来获取当前可读取记录信息实现的。
运行过程如下:
a.准备一行记录,1,2,3;1,null,null 前面三个字段是数据行数据,后面三个分别是 数据行隐藏id,事务id,回滚指针
b.事务a更新记录为所有数据*10,则记录行记录为 10,20,30;1,a,1,事务id更新了,回滚id更新为undolog指针记录,所以undolog中记录 1;1,2,3;1,null,null,第一个字段为undolog的id当然这个是我虚构出来的,实际上咩有这个字段,视为了更好的表述回滚指针,接着六个为元数据行的老数据。
c.事务b更新记录为所有数据+1,则记录行记录为 11,21,31;1,b,2,事务id又一次更新了,回滚id,更新为undolog指针记录,所以这是unlolog记录如下:
2;10,20,30;1,a,1
1;1,2,3;1,null,null
d.当ab事务中有查询,就会创建一个readview,readview作用就是根据当前事务id和记录隐藏id配合undolog查询记录行结果。结合记录行和undolog中记录得到一个读取视图。这样就避免了读取其他事务修改的数据。区别点在于在可重复读隔离级别,只有第一次查询的时候创建一次readview后面再次查询就不会创建直接读取前一次的即可,这样效率高,但是就算另一个事务提交了,再查询也得不到新提交的数据更新结果;而在读已提交隔离级别下每次查询的时候都会重新创建一次readview,这样另个一事务提交的数据就能够获取到。
可以看出,记录行回滚指针指向undolog,一个记录行在undolog中会有多行老版本的记录,每一行老版本都会根据回滚指针指向更老的数据记录。

提交操作:commit实际上是没有做任何事,因为记录行上实际上已经更新过了的。
回滚操作:rollback操作提交后,会根据事务id去undolog中查找回滚段,并且回滚对应的记录信息。
undolog维护:添加,开启事务的任何增删改都会添加该日志行,有一个purge线程一直在扫描undo日志,清理比当前执行的事务最小id的对应记录都清除掉,避免它无限增大。
redolog维护:当有任何写操作都会记录在redolog当中,它的大小是固定的,用于循环写,作用是当数据库宕机可以用它来恢复提交但是还没有存盘的事务记录。
理想mvcc实现差异:理想mvcc是每个事务将记录行都copy一个副本进行修改,但是理想mvcc对多行修改和回滚操作无能为力,所以MySQL没有按照最理想的mvcc来实现。

事务隔离级别及解决问题
ru-读未提交:除了使用锁,其他都没有使用,修改和读取都是在原行上进行操作。所以会有脏读、不可重复读和幻读。
rc-读已提交:使用锁和mvcc,避免了脏读,但是有不可重读和幻读问题。
rr-可重复读:使用锁和mvcc,避免了脏读和不可重复读问题,另外使用间隙锁也可以避免幻读问题。
ser-串行化:事务都是串行化处理,所以没有并发问题,但是效率非常低,极少使用。

事务的传播级别
传播级别一般是在例如spring等框架中使用的,规定的就是当前做的数据库处理,若没有在事务内怎么处理,若已经在一个事务内怎么处理。
1.若没有在事务内,处理方式就是三种:创建新事务来执行;以非事务形式执行;抛出异常。
2.若已经在一个事务内,处理方式有四种:在该事务内执行;将该事务挂起,以非事务形式执行;在该事务内新建一个事务嵌套执行;抛出异常。
一般七种事务传播界别,就是这几种处理方式的组合。即为若有事务则从1中选择一种方式,若没有事务则从2中选择一种方式。
一般默认事务类型,如果没有,就新建一个事务;如果有,就加入当前事务。适合绝大多数情况。

参考资料
什么是事务的传播特性
Spring的事务传播性与隔离级别
Mysql中的MVCC
MySQL InnoDB MVCC 机制的原理及实现

posted @ 2021-03-26 15:22  Q-JayLee  阅读(78)  评论(0)    收藏  举报