【问题标题】:Spring Transactional slows down complete processSpring Transactional减慢了整个过程
【发布时间】:2018-02-23 03:57:56
【问题描述】:

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

规格

Spring-orm 版本:3.2.18.RELEASE。

JDK 版本:1.8。

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

问题

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

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

仅供参考:我也收到很多消息,例如:“参与现有交易”。尝试通过将propagation=Propagation.NESTED 添加到processStage() 来解决此问题,但没有成功。

ProcessImpl 类。

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 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 中是不可取的吗?

【问题讨论】:

  • 尝试为@Transactional添加readonly
  • 我在这个过程中做了很多插入以及其他选择操作,所以,processStage 的 readOnly 仍然有效吗?
  • 不,那么 readonly 不适合您的情况
  • 您是否尝试在 processImpl 中仅使用 1 个 @Transactional 并删除 MyServiceImpl 方法中的 @Transactional

标签: java spring transactions transactional spring-orm


【解决方案1】:

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

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

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

在 Hibernate 上下文刷新期间放慢速度。 如果您更新太多对象,ORM 引擎(比如说 Hibernate)必须将它们下沉并将它们保存在内存中。从字面上看,Hibernate 必须具有所有旧状态和更新对象的所有新状态。有时它不会以最佳方式做到这一点。

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

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

我会遇到自我调用问题,这在事务中是不可取的吗?

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

【讨论】:

    【解决方案2】:

    这里的任何答案实际上都只是(非常充分的)猜想。在这种情况下,最好的办法是使用 Java 分析器并进行详细的 cpu 级别分析以准确了解发生了什么。

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

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

    【讨论】:

    • 已经这样做了,我很确定@Transactional 会导致非常糟糕的性能结果......
    猜你喜欢
    • 2018-10-09
    • 1970-01-01
    • 2010-12-22
    • 2020-09-23
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多