Spring Transactional减慢了整个过程

时间:2017-09-14 08:47:03

标签: java spring transactions transactional spring-orm

我正在尝试分析我有两个班级的情况。一个类是ProcessImpl,它是起点并在内部调用其他子事务。我不知道什么是错误的。 processImpl正在导入一些东西并将相关数据写入数据库。

  

功能

Spring-orm版本:3.2.18.RELEASE。

JDK版本:1.8。

Db :H2(记录任何db相同的性能)。

  

问题

如果我从@Transactional移除ProcessImpl.processStage(),则该过程需要 ~50秒 如果我保留@Transactional ProcessImpl.processStage(),则该过程需要 ~15分钟。 不知道为什么会这样。 我一直试图解决这个问题,但没有运气。请看下面的代码。

要求: 即使其中一个子事务失败,完整的processStage()也应完全或完全回滚。

Fyi:我也收到很多消息:“参与现有交易”。试图通过将propagation=Propagation.NESTED添加到processStage()来解决此问题,但无效。

  

ProcessImpl Class。

public class ProcessImpl {

    /*This is the big transaction that calls other transactional stuff from MyServiceImpl
    * This is starting point you can say for the process...
    * 
    * If we remove @Transactional from here the process is lightning fast 
    * With transactional : 15minutes
    * Without transactional : 50 seconds
    * */
    @Transactional
    public void processStage(){
        MyServiceImpl mp = new MyServiceImpl();
        //do some stuff
        mp.doWork1();

        //do more work
        mp.doWork2();

    }

}
  

MyServiceImpl Class

class MyServiceImpl{

    @Transactional
    public void doWork1(){
        Object o = doChildWork();
        // and more stuff
        //calls other class services and dao layers
    }

    @Transactional
    public void doWork2(){
        //some stuff
        doChildWork2();
        doChildWork();
        //more work
    }

    @Transactional
    public Object doChildWork(){
        return new Object(); //hypothetical, I am returning list and other collection stuff
    }

    @Transactional
    public Object doChildWork2(){
        return new Object(); //hypothetical, I am returning list and other collection stuff
    }

}

另外,我会在这里遇到自我调用问题,这在Transactional中是不可取的吗?

2 个答案:

答案 0 :(得分:3)

很难猜测代码中究竟发生了什么,但这可能存在问题:

锁定数据库级别。 当您在doWork1()doWork2()内更新相同的数据库对象时,可能会发生这种情况。由于两个方法都在一个事务中执行,因此doWork1()内完成的更新将在doWork2()完成之前提交。这两种方法都可能尝试锁定同一个DB对象并等待它。从技术上讲,它可以是任何数据库对象:表中的行,索引,整个表等。

分析您的代码并尝试找到可能被锁定的内容。您还可以在方法运行时查看数据库事务日志。所有流行的DB都提供有助于找到有问题的地方的功能。

在Hibernate上下文刷新期间减速。如果你更新了太多的对象,ORM引擎(比如说Hibernate)必须将它们接收并将它们保存在内存中。字面上,Hibernate必须具有所有旧状态和更新对象的所有新状态。有时这样做非常不理想。

您可以使用debug指出这一点。尝试找到最慢的地方,并检查那里正在调用的是什么。我可能会猜测,当hibernate更新缓存状态时,它会变慢。

还有一个问题。我看到您在MyServiceImpl期间使用构造函数创建了processStage()。我建议您通过弹簧自动装配替换此代码。首先,你使用它的方式不是它的设计使用方式,但理论上也可能以某种方式影响执行。

  

我会得到自我调用问题,这在Transactional中是不可取的吗?

不,它会很好地忽略所有注释。 doChildWork()内的doChildWork2()doWork2()的调用将被视为标准的java调用(只要您直接调用它们,spring就无法向它们添加任何“魔法”)。

答案 1 :(得分:0)

这里的任何答案都只是(非常了解情况)猜想。在这种情况下,最好的办法是掌握一个Java分析器并进行详细的CPU级别分析,以确切了解正在发生的事情。

我建议使用优秀的YourKit,但是你可以免费试用。

https://www.yourkit.com/docs/java/help/performance_bottlenecks.jsp