关于 java:Hibernate 继承和二级缓存代理

Hibernate inheritance and 2nd level cache proxies

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@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;

    ...
}

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

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

伪代码:

1
2
3
4
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)

在使用特殊逻辑从缓存hibernate构造实体加载期间:
对于字段,它通过变量类型(它的 EntityBase 类)而不是鉴别器(final Type[] types = subclassPersister.getPropertyTypes(); in DefaultLoadEventListener)检测类类型并调用方法
SessionImpl.internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) 巫婆"实例化"抽象类和初始化字段来自hibernate缓存

懒惰也一样


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

1
@Proxy(lazy=false)

如果你运行这个 GitHub 测试,你会看到 @Proxy(lazy=false) 解决了你的问题。