【问题标题】:Slow compilation with jOOQ 3.6+, plain SQL, and the javac compiler [duplicate]使用 jOOQ 3.6+、普通 SQL 和 javac 编译器进行慢速编译 [重复]
【发布时间】:2016-03-17 08:22:58
【问题描述】:

以下错误已报告给jOOQ user group。这似乎是 javac 编译器中的一个错误,与编译器在使用内部 DSL(如 jOOQ 是)的上下文中完成的相当“复杂”的类型推断工作有关。

鉴于该错误的一般性质,我将其记录在 Stack Overflow 上,以便其他人在遇到该错误时帮助他们应用变通方法。在较高的层面上,这似乎是由于JEP 101: Generalized Target-Type Inference 导致的编译器性能回归,它是在 Java 8 中引入的,过去曾导致 1-2 个问题。

使用 Maven 和 jOOQ 3.7 在 Windows 上使用 jdk 1.8.0_60 或 1.8.0_66 编译以下相对无害的类大约需要 20 秒:

import static org.jooq.impl.DSL.field;

import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

public class Test {
    public void method() {
        DSL.using(SQLDialect.MYSQL)
           .select()
           .where(DSL.trueCondition())
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
        ;
    }
}

pom.xml:

<project 
        xmlns="http://maven.apache.org/POM/4.0.0" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>compilation-issues</groupId>
    <artifactId>compilation-issues</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq</artifactId>
            <version>3.7.1</version>
        </dependency>
    </dependencies>
</project>

未出现此问题时的配置:

  • 使用 jOOQ 3.5(3.6.0 之前的任何版本)
  • 将 jOOQ 与生成的类一起使用,而不是使用上面的“普通 SQL”API
  • 使用 Java 7
  • 使用 Eclipse 编译器

【问题讨论】:

  • 去过那里:stackoverflow.com/questions/30707387/… - 很高兴看到您的解决方法。我得出了类似的结论:避免静态导入并使用大量中间变量来帮助类型推断......我认为这是错误:bugs.openjdk.java.net/browse/JDK-8051946
  • @assylias:嗯,我知道我以前见过类似的东西!感谢您的链接 - 那么这是重复的。我也为此向 Oracle 提交了另一个错误。让我们看看这是否增加了更多的权重:-/
  • @LukasEder,感谢您的错误报告:bugs.openjdk.java.net/browse/JDK-8145742,您可以看到它已被我们团队的一名成员关闭。原因是这些性能问题已在 JDK 9 中得到修复。因此,如果你们使用最新版本,则不会看到报告的问题。
  • 非常感谢@VicenteRomero。在我报告我的版本后的一段时间,我看到了我的报告的副本。是否有可能将其向后移植到 JDK 8?对于大量使用重载和泛型的人来说,这似乎是一个相当重要的问题......
  • 嗨@LukasEder,很抱歉回复得太晚了,我已经离开了很长时间。到目前为止,它还没有被反向移植,我认为它不会。我认为引起对该错误的注意的一种方法是发送电子邮件至:jdk8u-dev@openjdk.java.net 这些是维护 JDK 8 的人,他们可能会对向后移植该错误感兴趣

标签: java compilation java-8 jooq


【解决方案1】:

说明

在 jOOQ 3.6 中(当这个问题首次出现时),DSL.field() API 看到了 22 个新的重载,它们采用不同的 Row 类型作为参数:

看起来,对于上面这个特定的 API 用法,当 javac 编译器试图在所有可能的重载中找到最具体的重载时,新的重载会引起很多麻烦。以下解决方法可立即编译:

修复

正在对版本 3.9.03.8.13.7.43.6.5 进行修复,再次从公共 API 中删除这些方法,并提供不会导致任何重载问题的重命名替代。

解决方法

1。帮助编译器选择最具体的DSL.field()重载

import static org.jooq.impl.DSL.field;

import org.jooq.Field;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

public class Test {
    public void method() {
        Field<Object> f1 = field("client.id");
        Field<Object> f2 = field("client_id");
        DSL.using(SQLDialect.MYSQL)
           .select()
           .where(DSL.trueCondition())
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
        ;
    }
}

2。完全防止 and() 方法上下文中的目标类型推断

import static org.jooq.impl.DSL.field;

import org.jooq.Condition;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

public class Test {
    public void method() {
        Condition condition = field("client.id").eq(field("client_id"));
        DSL.using(SQLDialect.MYSQL)
           .select()
           .where(DSL.trueCondition())
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
        ;
    }
}

更多信息

这其实之前已经在 Stack Overflow 上报道过:

jOOQ 用户组也对此进行了讨论:

【讨论】:

    猜你喜欢
    • 2017-10-26
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 2020-05-02
    • 1970-01-01
    • 2012-10-21
    • 2014-08-04
    • 2017-10-04
    相关资源
    最近更新 更多