hibernate - Kotlin Hibernate OneToOne fetchtype.LAZY 立即运行所有查询

标签 hibernate kotlin

我正在接受培训,培训师使用 Java,我使用的是 Kotlin。到目前为止,我们在任何地方都得到了相同的结果,但在这里我无法让它发挥作用。

有2个实体类:

@Entity
data class Student(
        @Id
        @GeneratedValue
        var id: Long = 0,

        @Column(nullable = false)
        var name: String = "",

        @OneToOne()
        var passport: Passport? = null
)

@Entity
data class Passport(
        @Id
        @GeneratedValue
        var id: Long = 0,

        @Column(nullable = false)
        var number: String = ""
)

在测试类中,我使用实体管理器进行查询。
@RunWith(SpringRunner::class)
@SpringBootTest
class StudentRepositoryTest {
    val logger = LoggerFactory.getLogger(this.javaClass)

    @Autowired
    lateinit var studentRepository: StudentRepository

    @Autowired
    lateinit var entityManager: EntityManager

    @Test
    fun retrieveStudentAndPasswordDetails() {
        val student: Student? = entityManager.find(Student::class.java, 20001L)

        logger.info("Student -> $student")
        logger.info("Passport -> `${student?.passport}")
    }
}

当我以这种方式运行测试时,输出符合预期
Hibernate: 
    select
        student0_.id as id1_3_0_,
        student0_.name as name2_3_0_,
        student0_.passport_id as passport3_3_0_,
        passport1_.id as id1_1_1_,
        passport1_.number as number2_1_1_ 
    from
        student student0_ 
    left outer join
        passport passport1_ 
            on student0_.passport_id=passport1_.id 
    where
        student0_.id=?
2017-12-29 20:51:04.258 TRACE 17233 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [20001]
2017-12-29 20:51:04.263 TRACE 17233 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_1_1_] : [BIGINT]) - [40001]
2017-12-29 20:51:04.265 TRACE 17233 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([name2_3_0_] : [VARCHAR]) - [Ranga]
2017-12-29 20:51:04.266 TRACE 17233 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([passport3_3_0_] : [BIGINT]) - [40001]
2017-12-29 20:51:04.267 TRACE 17233 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([number2_1_1_] : [VARCHAR]) - [E123456]
2017-12-29 20:51:04.269  INFO 17233 --- [           main] i.StatisticalLoggingSessionEventListener : Session Metrics {
    19949 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    1097216 nanoseconds spent preparing 1 JDBC statements;
    227119 nanoseconds spent executing 1 JDBC statements;
    0 nanoseconds spent executing 0 JDBC batches;
    0 nanoseconds spent performing 0 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;
    0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
    0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
}
2017-12-29 20:51:04.269  INFO 17233 --- [           main] c.i.j.h.j.r.StudentRepositoryTest        : Student -> Student(id=20001, name=Ranga, passport=Passport(id=40001, number=E123456))
2017-12-29 20:51:04.269  INFO 17233 --- [           main] c.i.j.h.j.r.StudentRepositoryTest        : Passport -> `Passport(id=40001, number=E123456)

这看起来真的很好。使用连接调用查询,并显示两个日志输出。

使用 FetchType.LAZY
在这里,我将 FetchType.LAZY 添加到 OneToOne 注释中,这将使护照数据的检索等待到实际需要为止。
@Entity
data class Student(
        @Id
        @GeneratedValue
        var id: Long = 0,

        @Column(nullable = false)
        var name: String = "",

        @OneToOne(fetch = FetchType.LAZY)
        var passport: Passport? = null
)

这是我看到一些意外行为的地方。

我希望看到检索学生数据的查询,然后记录学生数据的输出。下一个查询以检索护照数据,最后是护照数据的日志。

当延迟加载会被完全忽略时,我希望仍然可以看到连接,但是有 2 个单独的查询,这似乎比没有延迟加载更糟。
Hibernate: 
    select
        student0_.id as id1_3_0_,
        student0_.name as name2_3_0_,
        student0_.passport_id as passport3_3_0_ 
    from
        student student0_ 
    where
        student0_.id=?
2017-12-29 21:03:53.401 TRACE 17380 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [20001]
2017-12-29 21:03:53.411 TRACE 17380 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([name2_3_0_] : [VARCHAR]) - [Ranga]
2017-12-29 21:03:53.412 TRACE 17380 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([passport3_3_0_] : [BIGINT]) - [40001]
Hibernate: 
    select
        passport0_.id as id1_1_0_,
        passport0_.number as number2_1_0_ 
    from
        passport passport0_ 
    where
        passport0_.id=?
2017-12-29 21:03:53.413 TRACE 17380 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [40001]
2017-12-29 21:03:53.415 TRACE 17380 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([number2_1_0_] : [VARCHAR]) - [E123456]
2017-12-29 21:03:53.427  INFO 17380 --- [           main] i.StatisticalLoggingSessionEventListener : Session Metrics {
    33422 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    569626 nanoseconds spent preparing 2 JDBC statements;
    1612599 nanoseconds spent executing 2 JDBC statements;
    0 nanoseconds spent executing 0 JDBC batches;
    0 nanoseconds spent performing 0 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;
    0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
    0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
}
2017-12-29 21:03:53.427  INFO 17380 --- [           main] c.i.j.h.j.r.StudentRepositoryTest        : Student -> Student(id=20001, name=Ranga, passport=Passport(id=40001, number=E123456))
2017-12-29 21:03:53.427  INFO 17380 --- [           main] c.i.j.h.j.r.StudentRepositoryTest        : Passport -> `Passport(id=40001, number=E123456)

@Transactional 注解

其他事情:当培训师在测试方法上运行没有 @Transacional 的测试时,会抛出异常。
就我而言,我是否使用此注释都没有区别。

最佳答案

我今天遇到了这个问题,经过大量研究和测试(Hibernate 编译时检测),我找到的解决方案是:

  • 添加 optional = false到我的 OneToOne
  • 添加 @LazyToOne(LazyToOneOption.PROXY)到我的属性
  • 制作子类 open以及 child 的所有属性 open

  • 在这些步骤之后, hibernate 停止自动获取。

    关于hibernate - Kotlin Hibernate OneToOne fetchtype.LAZY 立即运行所有查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48027924/

    相关文章:

    android - 如何在 Android Jetpack Compose 的 TextField 中更改输入字体大小

    hibernate - Grails hibernate 标准: How do I specify multiple criteria for one association?

    java - 为简单的 Pojo 数据对象启用自动提交?

    java - 如何在android中使用bitcoinj(walletappkit)从助记词创建比特币钱包

    android - 在 Kotlin 中是否有更干净的方法来设置日期时间

    spring - 更新 JPA(Hibernate) 实体 : transactional or non-transactional and why? 的更好方法是什么

    android - 在 Kotlin 中将 Array<String?> 转换为 Array<String>?

    java - 我无法理解 HQL 到 SQL 的翻译

    java - 无法避免 hibernate 记录 SQL 以使用 Spring Boot 和 Logback 进行控制台

    java - 从 Spring Web 应用程序捕获用户名以供触发器使用