gpt4 book ai didi

java - Hibernate 与 Spring Boot 和 Kotlin 急切加载整个对象图

转载 作者:太空宇宙 更新时间:2023-11-04 09:22:47 24 4
gpt4 key购买 nike

我设置了spring.jpa.open-in-viewfalse并且警告不再出现在日志中,因此这不是原因。

一旦 find() 就会获取整个对象图。或findById()方法被执行,所以我也不认为这是由序列化引起的(实体无论如何都没有实现 Serializable 接口(interface))。

所有对象关系都是多对一的,所有对象映射都被注释为惰性。

我能够避免急切加载的唯一方法是获取单个字段而不是整个实体,但这既耗时又脆弱,因此我不想使用此解决方案。

该应用程序使用 Hibernate 5.3.7 和 Spring Boot 2.1.0。我们拥有的较旧的 Java 应用程序没有这个问题;它使用 Hibernate 4.3.8 并且不使用 Spring Boot。

这是代码(从业务案例中精简以尝试查明问题)。

@Entity
@Table(name = "VT_Invoice")
class Invoice(
@Id
@Column(name = "InvoiceID")
val invoiceId: Long
) {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "EntityCode#ClientCore", referencedColumnName = "EntityCode#ClientCore")
var client: Client? = null
}
@Entity
@Table(name = "VT_ClientCore")
class Client(
@Id
@Column(name = "EntityCode#ClientCore")
val id: String
) {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "EntityCode#Branch", referencedColumnName = "EntityCode#Branch")
var branch: Branch? = null
}
@Entity
@Table(name = "VT_Branch")
class Branch(
@Id
@Column(name = "EntityCode#Branch")
val id: String
)
interface InvoiceRepository : JpaRepository<Invoice, Long>
@Service
class InvoiceRetrievalService(
@Autowired val invoiceRepository: InvoiceRepository
) {
@PersistenceContext
private lateinit var entityManager: EntityManager

fun fetchInvoice(invoiceId: Long): Invoice {
val hibernateInvoice = entityManager.find(Invoice::class.java, invoiceId)
val springInvoice = invoiceRepository.findById(invoiceId)
return hibernateInvoice
}
}
<小时/>

编辑

调试Hibernate代码后发现,急切加载就是由DefaultLoadEventListener.proxyOrLoad()里面的这 block 代码触发的。 :

        if ( !persister.hasProxy() ) {
return load( event, persister, keyToLoad, options );
}

AbstractEntityPersister.hasProxy() Hibernate 的两个版本之间的实现有所不同。

hibernate 4.3.8:

    public boolean hasProxy() {
return entityMetamodel.isLazy();
}

entityMetamodel.isLazy()为 true,因此跳过链接对象加载。

hibernate 5.3.7:

    public boolean hasProxy() {
// skip proxy instantiation if entity is bytecode enhanced
return entityMetamodel.isLazy() && !entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
}

entityMetamodel.isLazy()为 false,因此加载链接的对象。对字节码增强的检查结果是无关紧要的。

这是我通过调查所能得到的信息。我无法确定为什么两个版本的 Hibernate 都会初始化 lazy属性不同;它被写入到多个地方,但我设置的断点都没有被击中,所以我假设它是通过某处的反射初始化的。

最佳答案

事实证明,lazy 属性是在这段 Hibernate 代码中初始化的:

lazy = persistentClass.isLazy() && (
// TODO: this disables laziness even in non-pojo entity modes:
!persistentClass.hasPojoRepresentation() ||
!ReflectHelper.isFinalClass( persistentClass.getProxyInterface() )
);

差异源于 isFinalClass() 检查 - 默认情况下,类在 Kotlin 中是 Final,但在 Java 中不是。让实体类开放解决了问题。

在重新阅读我的问题时,我发现我忘记提及没有此问题的旧应用程序是用 Java 编写的。我会更新问题。对此感到抱歉。

关于java - Hibernate 与 Spring Boot 和 Kotlin 急切加载整个对象图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58114438/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com