事务总结

时间:2020-01-28 15:40:28   收藏:0   阅读:83

 有时候一个业务需要多次操作数据库,比如转账:

技术分享图片

如果reduce()执行成功,add执行失败,那钱是转出去了,但对方并没有收到,钱转丢了。

使用事务可解决此问题。

 

 事务:逻辑上的一组操作,要么全部成功,要么全部失败。

 

 


 

 

事务的4个特性

 

 


 

 

如果没做到隔离性,可能会引发读写问题

读问题:

写问题:

 

 


  

 

脏读     读取另一个事务未提交的数据

原本数据库中的数据是正确的、干净的,

B事务更改了数据库中的数据,

A事务读取数据库中的数据(被事务B修改后的数据),

事务B发生错误,将数据库中的数据回滚成原本干净的数据,A读取到的数据变成了无效数据、脏数据。

但事务A什么都不知道,使用之前读取到的数据(脏数据)做一些操作。

 

 

示例    B取款的同时,A转账给B

技术分享图片

虽然2个事务是并发执行的,但实际上,执行具体代码时仍有先后顺序。

 

 


 

  

不可重复读     前后多次读取,读取到的数据内容不一致(期间已被其它事务修改)

 

事务A比较大,前后需要多次从数据库读取同一段数据。

 

开始事务

前一次从数据库读取数据,赋给一些变量来使用,

使用这些变量来做一些操作,

随着代码的执行,这些变量逐渐被销毁(方法调用结束,局部变量被销毁;对象长时间闲置,被gc回收等),

 

之后需要再次使用这些数据,因为变量已被销毁,只有重新从数据库读取数据(执行的仍是之前的sql语句)来使用,

但这2次读取期间,有其它的事务修改了数据库中的这些数据的内容,

2次读取到的数据不一致(不是重复的),称为不可重复读。

但事务A不知道前后的数据不一致,仍然使用第二次读取的数据做一些操作。

提交事务。

 

第一次读取的数据已经无效了,使用这些数据做的操作无效,即前面部分做的操作与后面部分做的操作对不上。

 

 


 

 

虚读(幻读)  前后多次读取,读取到的记录数不一致(期间已被其它事务修改)

虚读和不可重复读差不多,都是前后读取相同的内容(执行一样的sql查询),

不可重复读是记录数没变化、但记录的内容被其它事务修改了(update  xxx_tb  set  xxx=xxx),

虚读是读取到的记录数变了(其它事务使用insert、delete修改了数据库中读取的部分,导致记录总数不一致)。

 

 


 

 

可通过设置事务的隔离级别,来解决读问题。

 

事务的4种隔离级别

一般是折中使用第2、3项,mysql用Repeatable read,oracle用Read committed。

 

 


 

 

事务的传播行为

 技术分享图片

事务管理是添加在业务层的,给Service中的方法添加事务管理。

 

一般情况下:

就可以完成业务。

 

 

但有时候业务特别复杂,需要调用业务层的其它方法:

技术分享图片

包括调用其它Service的方法、本Service的其它的方法。

调用的方法可能添加了事务,对于Service.x()带过来的事务(被调方法传播过来的事务),该如何处理?

事务的传播行为就是:在业务层的方法相互调用时,规定主调方法定义自身的事务管理(是否使用被调方法的事务)。

 

 


 

  

Spring中的7种事务传播行为

 

以下面的调用为例:

技术分享图片

 

 

大致可分为3类:(红色标示的项是常见的,只需记住红色标示的项)

 

(1)保证多个操作在同一个事务中

如果被调方法有事务,主调方法就使用被调方法的事务;如果被调方法没有事务,会创建一个新事务,管理主调方法。

会把主调方法的其它代码包含进来,一起管理。被调方法指的是业务层的其它其它方法Service1.x(),主调方法指的是z(),包括Service1.x() + Dao2.c() 。

required   要求、需要、必需的,对于主调方法,事务是必需的

 

如果被调方法有事务,主调方法就使用被调方法的事务;如果被调方法没有事务,主调方法就不使用事务。

supports,有就支持,没有就算了(都不使用事务)。

 

如果被调方法有事务,主调方法就使用被调方法的事务;如果被调方法没有事务,则抛出异常。

 

 

 

(2)保证多个操作不在同一个事务中

requires_new   对于主调方法,事务是必需的,且事务要是新建的(只管里主调方法的其它部分,被调方法的事务管理维持原状)。

会新建一个事务,管理主调方法(的其它部分),被调方法的事务管理维持原状。

 

不管被调方法有没有事务,主调方法都不使用事务(其它部分不使用,被调方法的事务管理维持原状)。

not_supported,主调方法不支持事务。

 

如果被调方法有事务,直接抛出异常。

never,决不能有事务。

 

 

 

(3)嵌套式事务

在主调方法执行前、被调方法执行的前后设置还原点,失败时可以回滚到某个还原点。

执行主调方法之前先设置一个还原点,执行主调方法的其它代码(如果有)。

如果执行失败,回滚到之前的还原点;如果执行成功,再设置一个还原点,执行被调方法(如果被调方法有事务,会执行被调方法的事务)。

如果被调方法执行失败,回滚到之前的某个还原点(可设置),如果被调方法执行成功,设置一个还原点,执行后续的其它代码。

如果执行失败,回滚到之前的某个还原点(可设置)。

 

原文:https://www.cnblogs.com/chy18883701161/p/12237229.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!