在以下最小可重现示例中,延迟加载对我不起作用。 (我确实需要延迟加载,因为我需要在代码库中的多个地方依赖它。)
我得到的错误是在代码之后:
import jakarta.persistence.*
@Entity
open class X(
@Id val k: Int,
@OneToOne(mappedBy = "xField", fetch = FetchType.LAZY)
var yField: Y? = null
) {
constructor() : this(0)
open fun getY(): Y? {
return yField
}
open fun setY(y: Y?) {
this.yField = y
}
}
@Entity
open class Y(
@Id
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "x_k")
val xField: X,
val nField: Int
) {
constructor() : this(X(0), 0)
open fun getX(): X {
return xField
}
open fun getN(): Int {
return nField
}
}
fun main() {
val entityManagerFactory = Persistence.createEntityManagerFactory("your-persistence-unit")
val entityManager = entityManagerFactory.createEntityManager()
try {
entityManager.transaction.begin()
val x = entityManager.find(X::class.java, 0) ?: throw IllegalStateException("cannot find X 0")
println("found X")
println(x.k)
println(x.getY()) // Should print proxy or actual Y entity
println(x.getY()?.getN()) // Should print 7 if Y is correctly lazily loaded
entityManager.transaction.commit()
} catch (e: Exception) {
entityManager.transaction.rollback()
e.printStackTrace()
} finally {
entityManager.close()
entityManagerFactory.close()
}
}
以下是运行代码时遇到的两个异常(一个警告和一个错误):
00:38:27.269 [main] WARN org.hibernate.metamodel.internal.EntityRepresentationStrategyPojoStandard - HHH000305: Could not create proxy factory for:X
org.hibernate.HibernateException: Getter methods of lazy classes cannot be final: X#getK
at org.hibernate.proxy.pojo.ProxyFactoryHelper.validateGetterSetterMethodProxyability(ProxyFactoryHelper.java:80)
at org.hibernate.metamodel.internal.EntityRepresentationStrategyPojoStandard.createProxyFactory(EntityRepresentationStrategyPojoStandard.java:241)
at org.hibernate.metamodel.internal.EntityRepresentationStrategyPojoStandard.<init>(EntityRepresentationStrategyPojoStandard.java:147)
at org.hibernate.metamodel.internal.ManagedTypeRepresentationResolverStandard.resolveStrategy(ManagedTypeRepresentationResolverStandard.java:62)
at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:512)
at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:140)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:92)
at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:75)
at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.processBootEntities(MappingMetamodelImpl.java:247)
at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.finishInitialization(MappingMetamodelImpl.java:185)
at org.hibernate.internal.SessionFactoryImpl.initializeMappingModel(SessionFactoryImpl.java:321)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:271)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1458)
at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:55)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:80)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at TMainKt.main(tMain.kt:40)
at TMainKt.main(tMain.kt)
java.lang.NullPointerException: Cannot invoke "org.hibernate.sql.results.graph.Initializer.asEntityInitializer()" because "initializer" is null
at org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl$CircularFetchAssembler.resolveCircularInitializer(CircularBiDirectionalFetchImpl.java:226)
at org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl$CircularFetchAssembler.assemble(CircularBiDirectionalFetchImpl.java:138)
at org.hibernate.sql.results.graph.embeddable.internal.AbstractNonAggregatedIdentifierMappingInitializer.extractRowState(AbstractNonAggregatedIdentifierMappingInitializer.java:228)
at org.hibernate.sql.results.graph.embeddable.internal.AbstractNonAggregatedIdentifierMappingInitializer.initializeInstance(AbstractNonAggregatedIdentifierMappingInitializer.java:169)
at org.hibernate.sql.results.graph.embeddable.internal.EmbeddableAssembler.assemble(EmbeddableAssembler.java:34)
at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.initializeIdentifier(AbstractEntityInitializer.java:370)
at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.resolveEntityKey(AbstractEntityInitializer.java:347)
at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.resolveKey(AbstractEntityInitializer.java:289)
at org.hibernate.sql.results.internal.InitializersList.resolveKeys(InitializersList.java:82)
at org.hibernate.sql.results.internal.StandardRowReader.coordinateInitializers(StandardRowReader.java:109)
at org.hibernate.sql.results.internal.StandardRowReader.readRow(StandardRowReader.java:87)
at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:179)
at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33)
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:361)
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:168)
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:93)
at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31)
at org.hibernate.loader.ast.internal.SingleIdLoadPlan.load(SingleIdLoadPlan.java:146)
at org.hibernate.loader.ast.internal.SingleIdLoadPlan.load(SingleIdLoadPlan.java:106)
at org.hibernate.persister.entity.AbstractEntityPersister.initializeLazyPropertiesFromDatastore(AbstractEntityPersister.java:1552)
at org.hibernate.persister.entity.AbstractEntityPersister.initializeLazyProperty(AbstractEntityPersister.java:1497)
at org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor.lambda$loadAttribute$0(LazyAttributeLoadingInterceptor.java:112)
at org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper.performWork(EnhancementHelper.java:206)
at org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor.loadAttribute(LazyAttributeLoadingInterceptor.java:82)
at org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor.fetchAttribute(LazyAttributeLoadingInterceptor.java:78)
at org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor.handleRead(LazyAttributeLoadingInterceptor.java:59)
at org.hibernate.bytecode.enhance.spi.interceptor.AbstractInterceptor.readObject(AbstractInterceptor.java:152)
at X.$$_hibernate_read_yField(tMain.kt)
at X.getY(tMain.kt:12)
at TMainKt.main(tMain.kt:49)
at TMainKt.main(tMain.kt)
Process finished with exit code 0
这是我的 build.gradle.kts 文件:
plugins {
kotlin("jvm") version "2.0.0"
id("org.hibernate.orm") version "6.2.28.Final"
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.hibernate:hibernate-core:6.2.28.Final")
implementation("jakarta.persistence:jakarta.persistence-api:3.1.0")
implementation("org.postgresql:postgresql:42.5.0")
implementation("ch.qos.logback:logback-classic:1.2.11")
}
hibernate {
enhancement {
enableLazyInitialization.set(true)
enableDirtyTracking.set(true)
enableAssociationManagement.set(true)
enableExtendedEnhancement.set(true)
}
}
tasks.withType<JavaCompile> {
options.compilerArgs.add("-Xplugin:org.hibernate.orm.enhance")
}
持久性.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
<persistence-unit name="your-persistence-unit" transaction-type="RESOURCE_LOCAL">
<class>X</class>
<class>Y</class>
<properties>
<!-- JDBC Database Connection Settings -->
<property name="jakarta.persistence.jdbc.driver" value="org.postgresql.Driver"/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/main"/>
<property name="jakarta.persistence.jdbc.user" value="main"/>
<property name="jakarta.persistence.jdbc.password" value=""/>
<!-- Hibernate Properties -->
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
和应用程序属性:
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
以及数据库中的行:
main=> \d+ x
Table "public.x"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
k | integer | | not null | | plain | | |
Indexes:
"x_pkey" PRIMARY KEY, btree (k)
Referenced by:
TABLE "y" CONSTRAINT "fkl54y40sycpm07uk682c1k3ivs" FOREIGN KEY (x_k) REFERENCES x(k)
Access method: heap
main=> \d+ y
Table "public.y"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
nfield | integer | | not null | | plain | | |
x_k | integer | | not null | | plain | | |
Indexes:
"y_pkey" PRIMARY KEY, btree (x_k)
Foreign-key constraints:
"fkl54y40sycpm07uk682c1k3ivs" FOREIGN KEY (x_k) REFERENCES x(k)
Access method: heap
main=> select * from x ;
k
---
0
(1 row)
main=> select * from y ;
nfield | x_k
--------+-----
7 | 0
(1 row)
我已经广泛尝试了各种方法,但就是行不通。
更新:我通过将所有字段设置为
open
来消除第一个异常。下面的代码只给出了第二个例外:
import jakarta.persistence.*
@Entity
open class X(
@Id open val k: Int,
@OneToOne(mappedBy = "xField", fetch = FetchType.LAZY)
open var yField: Y? = null
) {
constructor() : this(0)
open fun getY(): Y? {
return yField
}
open fun setY(y: Y?) {
this.yField = y
}
}
@Entity
open class Y(
@Id
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "x_k")
open val xField: X,
open val nField: Int
) {
constructor() : this(X(0), 0)
open fun getX(): X {
return xField
}
open fun getN(): Int {
return nField
}
}
fun main() {
val entityManagerFactory = Persistence.createEntityManagerFactory("your-persistence-unit")
val entityManager = entityManagerFactory.createEntityManager()
try {
entityManager.transaction.begin()
val x = entityManager.find(X::class.java, 0) ?: throw IllegalStateException("cannot find X 0")
println("found X")
println(x.k)
println(x.getY()) // Should print proxy or actual Y entity
println(x.getY()?.getN()) // Should print 7 if Y is correctly lazily loaded
entityManager.transaction.commit()
} catch (e: Exception) {
entityManager.transaction.rollback()
e.printStackTrace()
} finally {
entityManager.close()
entityManagerFactory.close()
}
}
哇,有时,就像升级到最新的稳定版本一样简单。我将
hibernate
工件版本更改为 6.5.2.Final
,延迟加载开始完美运行!
将这个问题留在这里,因为这通常是一件棘手的事情,其他人可能会遇到困难。 (ChatGPT-4o 和 Claude 都被难住了!)