欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring中service事务配置传播隔离等关系

程序员文章站 2022-07-13 14:36:39
...
    工作中正好碰到这个问题,于是学习以下两个文章。先介绍了一些知识。后加入了对知识的分析,方便理解。并对可能的原理进行推测,以后有空看源码。
    文章一
    文章二

    做java的WEB开发,通常都是分层的,包括action(controller层),service层,dao层。这里重点说说service层,也就是业务逻辑层的事务问题。

    1.首先说一说action(controller)层
    这一层是与web应用密切相关的,主要是处理request与response。把请求中的东西拿出来,作为业务层的输入,再把业务层的结束包装(处理)后,产生响应对象。

    代码要求:功能分层来说,这个action层功能主要是处理web的数据的,通常是不应该含有事务逻辑的,如果有请另包装到到一个service中。我经常看到一些代码把request传递到service中处理,问过原因,说是参考其它人的代码也是这么写的。所以告诉原因很重要。业务通用性来讲,业务逻辑不一定都是给web用的,总不能让非web的应用,数据包装成request来用吧。

    2.spring注解事务
    我们现在都用注解方式,很多时候只是写一个@Transactional。实际上后面可以设置多种参数。
    有表明传播性与隔离级别。比如:
    @Transactional(propagation = Propagation.REQUIRES_NEW)。不写的情况下,默认是:PROPAGATION_REQUIRED。
    也有表明引起事务回滚的异常类:
    @Transaction(noRollbackFor=RuntimeException.class)
    @Transaction(RollbackFor=Exception.class)
    不写的情况下,默认是:RuntimeException,只回滚unchecked异常。
    另外还有一个readOnly = true,最后会讲。
    默认配置,能够满足正常的需要,没有特殊情况就只要一个@Transaction。但要注意后面提到的异常处理。

    3.关于spring注解事务的异常
    代码要求:按默认情况配置,也就是不配置。自定义业务中异常的时候,让自定义的异常继承自RuntimeException,这样抛出的时候才会被Spring默认的事务处理准确处理。如果是一个servive中产生了checked异常,请在本service方法中处理掉或者另抛出unchecked一场,否则如果有外层service,将不知道要不要回滚整个事务。
    通常我们的项目中,注意异常的处理就可以了。

    以下讨论的回滚都指unchecked异常,先是主要的几种传播与隔离配置。
    3.PROPAGATION_REQUIRED
    一般文章介绍:默认事务类型,如果没有,就新建一个事务;如果有,就加入当前事务。适合绝大多数情况。

    结论:
    内外都无trycatch情况:
    这样在方法中任何地方发生unchecked异常将触发整个方法的回滚。
    无论内外层产生unchecked异常,都回滚。

    如果有trycatch情况:
    外层发生了unchecked异常,但被外层trycatch了,那是不会回滚的。
    内层发生了unchecked异常,但外层有trycatch,但还是回滚了。按说外层的AOP是感受不到抛出的异常的,怎么会回滚呢?我猜测是内层的AOP也抛出了一个不能被外层trycatch的异常,而被外层的AOP感受到了。
    内层发生了unchecked异常,但内层有trycatch,内层不回滚,如果外层正常,也不回滚了。


    4.PROPAGATION_NESTED
    一些文章先测试再讲规则,有点不知其所以然的感觉,所以我先查查什么是嵌套事务及其原则?
    嵌套事务是一个外部事务的一个子事务,是一个外部事务的一个组成部分,当嵌套事务发生异常而回滚,则会恢复到嵌套事务的执行前的状态,相当于嵌套事务未执行。
    如果外部事务回滚,则嵌套事务也会回滚!!!外部事务提交的时候,嵌套它才会被提交。
    定义明确了,无论是交给spring处理NESTED事务,还是数据库处理NESTED事务,或者你设计什么事务时,原则都应该一样。

     当所调用的方法为NESTED事务,该事务的回滚可以不影响到调用者的事务
     当然如果子事务没有trycatch,异常冒泡而出,就将触发调用者事务的回滚。子事务有了trycatch就不会影响到外部调用者事务了,不会触发整个方法的回滚。

    而调用者出现unchecked异常,却能触发所调用的nested事务的回滚!

    5.PROPAGATION_REQUIRES_NEW
    更少用到了此情况,通常可以将此部分代码放在事务之外执行 实在剥离不开才会用到。当被调用时,就相当于暂停(挂起)当前事务,先开一个新的事务去执行REQUIRES_NEW的方法,如果REQUIRES_NEW中的异常得到了处理那么他将不影响调用者的事务,同时,调用者之后出现了异常,同样也不会影响之前调用的REQUIRES_NEW方法的事务.
    有个猜测:但是如果如果内部REQUIRES_NEW中的异常没有处理,异常冒泡会影响到调用者吧!
  
    6.REQUIRES_NEW与NESTED比较
    PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, REQUIRES_NEW 完全是一个新的事务,而NESTED 则是外部事务的子事务,如果外部事务commit,嵌套事务也会被commit, 这个规则同样适用于rollback。
    PROPAGATION_NESTED可以在外层rollback所有内层的事务。REQUIRES_NEW不行。

    后面再介绍几个配置参数,简单介绍就明白了。
    7.PROPAGATION_SUPPORTS:如果没有,就以非事务方式执行;如果有,就使用当前事务。

    8.PROPAGATION_NOT_SUPPORTED:如果没有,就以非事务方式执行;如果有,就将当前事务挂起。即无论如何不支持事务。
    例子如下面的文章:微信文章
    上面的文章中,介绍了一个事务的业务中,突然要加一个非事务的方法。非事务的方法不能是本对象里的方法,不能是private方法,只能是public的,而且只有另写对象,以注入的方式,才能实现事务之间的关系处理。因为AOP代理了这些方法所在的业务对象。

    9.PROPAGATION_NEVER:如果没有,就以非事务方式执行;如果有,就抛出异常。

    10.PROPAGATION_MANDATORY:如果没有,就抛出异常;如果有,就使用当前事务。

    11.引伸的配置@Transactional(readOnly = true)
    从这一点设置的时间点开始(时间点a)到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!(查询中不会出现别人在时间点a之后提交的数据)。
    应用场合:
    如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;
    如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。
    【注意是一次执行多次查询来统计某些信息,这时为了保证数据整体的一致性,要用只读事务】
    在将事务设置成只读后,相当于将数据库设置成只读数据库,此时若要进行写的操作,会出现错误。

    项目中的使用情况:目前的项目几乎没有实时的,多条相关的只读查询,不需要这个设置。

    注:以上的总结都没有时间亲测,只是看一些文章的总结。如有错误,欢迎指正。spring中service事务配置传播隔离等关系
            
    
    博客分类: spring springTransactional 

-------------------------------------------------------------------------
    另记录一个问题解决:之前部署的一个应用,平时正常,但经常早上不能访问,很是着急,上班前要花时间远程处理。发现是应用服务器与数据库服务器的网线直连不通了,时间紧就重启下。后来发现只要网络禁用再启动就行了。
    后来几次后没找到原因,没条件换硬件或者不断修改配置来测试。突然想到定时任务,于是查到可以自动禁用启用网络的命令。至此,这个麻烦的问题再也没出现过了。

spring中service事务配置传播隔离等关系
            
    
    博客分类: spring springTransactional 
  • spring中service事务配置传播隔离等关系
            
    
    博客分类: spring springTransactional 
  • 大小: 47.9 KB