Hibernate 继承和二级缓存代理

dem*_*101 5 java orm caching hibernate hibernate-mapping

简单的应用程序在以下实体结构中工作错误

@Entity(name="some_table")
@Inheritance(strategy= InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn( name="TYPE", discriminatorType=DiscriminatorType.STRING )
abstract class EntityBase {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    @Column
    private int id;
}

@Entity
@DiscriminatorValue("EntityA")
@Cacheable
class EntityA extends EntityBase {
    @Column
    private int aColumn;
...
}

@Entity
@DiscriminatorValue("EntityB")
@Cacheable
class EntityB extends EntityBase {
    @Column
    private int bColumn;
...
}

@Entity(name="holder_table")
@Cacheable
class HolderEntity {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    @Column
    private int id;

    @ManyToOne(fetch=FetchType.LAZY)
    EntityBase holdedEntity;

    ...
}
Run Code Online (Sandbox Code Playgroud)

对于首次加载或没有缓存,一切正常

从缓存加载 HolderEntity 实例后,holdedEntity 字段由 EntityBase 类型(抽象类)的对象初始化。

伪代码:

def a = HolderEntity.get(1)
assert a.holdedEntity.class!=EntityBase //ok
a = HolderEntity.get(1) // load from cache
assert a.holdedEntity.class!=EntityBase //fails (actually EntityBase_$$_jvstbbe_0)
Run Code Online (Sandbox Code Playgroud)

在从缓存加载期间,hibernate使用特殊逻辑构造实体:对于字段,它通过变量类型(它是EntityBase类)而不是鉴别器(在DefaultLoadEventListener中的final Type[] types = subclassPersister.getPropertyTypes();)检测类类型并调用方法SessionImpl.internalLoad (字符串entityName,可序列化id,布尔值eager,布尔值可为空)通过hibernate缓存中的数据“实例化”抽象类和初始化字段

对于存储在AbstractEntityPersister.EntityMetamodel中的heldEntity类类型的延迟加载和急切加载,它的工作原理相同。看起来,缓存的字段类型是静态的,但它应该取决于字段的实例

如何在不禁用hibernate L2缓存的情况下解决这个问题?

Hibernate 4.3.8(也测试了 4.3.6 和 4.3.11)

更新: 测试类

Vla*_*cea 4

这是因为 Hibernate 使用代理进行惰性关联。如果要禁用代理,则需要将@Proxy注解添加到实体类映射中:

@Proxy(lazy=false)
Run Code Online (Sandbox Code Playgroud)

如果您运行此 GitHub 测试,您会发现它@Proxy(lazy=false)解决了您的问题。