Hibernate 继承和二级缓存代理
Hibernate inheritance and 2nd level cache proxies
简单的应用程序在使用以下实体结构时会出错
@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(抽象 class)的对象初始化。
伪代码:
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)
在使用特殊逻辑从缓存休眠构造实体加载期间:
对于字段,它通过变量类型(它是 EntityBase class)检测 class 类型,而不是鉴别器(final Type[] types = subclassPersister.getPropertyTypes();在 DefaultLoadEventListener) 中调用方法
SessionImpl.internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) "instantiate" abstract class and init fields by data from 数据休眠缓存
对于 holdedEntity 的延迟加载和急切加载,它的工作原理相同
Class 类型存储在 AbstractEntityPersister.EntityMetamodel 中。看起来,缓存的字段类型是静态的,但它应该取决于字段的实例
如何在不禁用休眠二级缓存的情况下解决?
Hibernate 4.3.8(也测试了 4.3.6 和 4.3.11)
更新:
test class
那是因为 Hibernate 使用代理进行惰性关联。如果你想禁用代理,你需要添加 @Proxy 注释到你的实体 class 映射:
@Proxy(lazy=false)
如果您 运行 this GitHub test,您会发现 @Proxy(lazy=false)
解决了您的问题。
简单的应用程序在使用以下实体结构时会出错
@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(抽象 class)的对象初始化。
伪代码:
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)
在使用特殊逻辑从缓存休眠构造实体加载期间:
对于字段,它通过变量类型(它是 EntityBase class)检测 class 类型,而不是鉴别器(final Type[] types = subclassPersister.getPropertyTypes();在 DefaultLoadEventListener) 中调用方法
SessionImpl.internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) "instantiate" abstract class and init fields by data from 数据休眠缓存
对于 holdedEntity 的延迟加载和急切加载,它的工作原理相同 Class 类型存储在 AbstractEntityPersister.EntityMetamodel 中。看起来,缓存的字段类型是静态的,但它应该取决于字段的实例
如何在不禁用休眠二级缓存的情况下解决?
Hibernate 4.3.8(也测试了 4.3.6 和 4.3.11)
更新: test class
那是因为 Hibernate 使用代理进行惰性关联。如果你想禁用代理,你需要添加 @Proxy 注释到你的实体 class 映射:
@Proxy(lazy=false)
如果您 运行 this GitHub test,您会发现 @Proxy(lazy=false)
解决了您的问题。