Spring 交易会减慢整个过程

Spring Transactional slows down complete process

我正在尝试分析我有两个 classes 的情况。一个 class 是 ProcessImpl,它是起点并在内部调用其他 child transactions.I 不知道出了什么问题。 processImpl 正在导入一些东西并将相关数据写入数据库。

Specs

Spring-orm 版本:3.2.18.RELEASE。

JDK 版本:1.8。

Db : H2(在任何数据库上都记录了相同的性能)。

Issue

如果我从 ProcessImpl.processStage() 中删除 @Transactional,该过程需要 ~ 50 秒 如果我将 @TransactionalProcessImpl.processStage() 保持一致,则该过程需要 ~ 15 分钟 。 不知道为什么会这样。 长期以来,我一直在努力解决这个问题,但没有运气。请看下面的代码。

要求: 完整的 processStage() 应该完成或完全回滚,即使 child 事务之一失败。

仅供参考:我也收到很多消息,例如:"Participating in existing transaction"。试图通过将 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 中是不可取的吗?

很难猜测您的代码中到底发生了什么,但可能存在以下问题:

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

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

在 Hibernate 上下文刷新期间放慢速度。 以防更新太多对象时 ORM 引擎(比方说 Hibernate)必须接收它们并将它们保存在内存中。从字面上看,Hibernate 必须具有更新对象的所有旧状态和所有新状态。有时它不是以最佳方式执行此操作。

您可以使用调试来指出这一点。尝试找到最慢的地方并检查那里到底调用了什么。我可能猜想它会在休眠更新缓存状态时变慢。

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

will I get self invocation issue, which is not advisable in Transactional?

不,忽略所有注释也能正常工作。在 doWork2() 中调用 doChildWork()doChildWork2() 将被视为标准 java 调用(spring 无法向它们添加任何“魔法”,只要你直接调用它们)。

这里的任何答案实际上都只是(消息灵通的)推测。在这种情况下,最好的办法是使用 Java 分析器并进行详细的 cpu 级别分析以准确计算出发生了什么。

我推荐优秀的 YourKit,它是商业的,但你可以免费试用。

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