Hibernate的延迟加载

来源:互联网 发布:大学生单片机比赛 编辑:程序博客网 时间:2024/05/08 23:54

hibernate中,延迟加载大致可以分为两类,一类是延迟属性加载,另一类是延迟关联实体加载。

普通属性:分两种情况,一种是集合属性,一种是非集合属性(如String、Integer......)

集合属性的延迟加载通过PersistentSet、 PersistentList、PersistentBag、PersistentMap、PersistentSortedMap、PersistentSortedSet作为代理类来实现,代理类中保存了session以及owner属性,owner属性表示了集合属性所属的one侧的实体。

非集合类属性的延迟加载相对比较复杂。仅通过@Basic(fetch = FetchType.LAZY)注解是无法实现延迟加载的。需要让实体实现FieldHandled接口,声明FieldHandler属性,通过拦截器原理注入对应的FieldHandler属性,起到类似于上述代理类的作用,FieldHandler同样也保持了session,以及需要延迟加载的属性。

@Basic(fetch = FetchType.LAZY)@Column(name="CONTENT")public String getContent() {    if (fieldHandler != null) {        return (byte[]) fieldHandler.readObject(this, "content", content);    }    return null;}public void setContent(byte[] content) {    this.content = content;}@Overridepublic void setFieldHandler(FieldHandler handler) {    this.fieldHandler = handler;}@Overridepublic FieldHandler getFieldHandler() {    return this.fieldHandler;}
Hibernate官网对非结合属性的延迟加载有如下的评论:

Lazy property loading requires buildtime bytecode instrumentation. If your persistent classes are not enhanced, Hibernate will ignore lazy property settings and return to immediate fetching.

A different way of avoiding unnecessary column reads, at least for read-only transactions, is to use the projection features of HQL or Criteria queries. This avoids the need for buildtime bytecode processing and is certainly a preferred solution.

大致的意思就是:应该是因为,我们并未用到编译时字节码增强技术的原因。如果只对部分property进行延迟加载的话,hibernate还提供了另外的方式,也是更为推荐的方式,即HQL或者条件查询。

更为推荐的方式说白了就是在查询的时候就过滤掉不需要的属性,以下列出HQL和Criterial的两种实现方法:

// criterial实现criteria.setProjection(                Projections.projectionList().add(Projections.property("id"), "id")                        .add(Projections.property("age"), "age")).setResultTransformer(                Transformers.aliasToBean(User.class));// HQL实现Query query = session.createQuery("select u.id as id,u.age as age from User u where u.id=2");query.setResultTransformer(Transformers.aliasToBean(User.class));


关联实体:分两种情况,一种是多对一,另一种是一对一。

关联实体是多个实体时(包括一对多、多对多):此时关联实体将以集合的形式存在,Hibernate 将使用 PersistentSet、PersistentList、PersistentMap、PersistentSortedMap、PersistentSortedSet 等集合来管理延迟加载的实体。这就是前面所介绍的情形。

关联实体是单个实体时(包括一对一、多对一):当 Hibernate 加载某个实体时,延迟的关联实体将是一个动态生成代理对象。Hibernate 使用 Javassist 项目动态生成的代理类——当 Hibernate 延迟加载关联实体时,将会采用 Javassist 生成一个动态代理对象,这个代理对象将负责代理“暂未加载”的关联实体。但是在一对一关系中,延迟加载是有陷阱的。

一对一关联一般有两种形式,一种是主键关联;另一种是外键关联。

主键关联:

Husband:id,name
Wife:id,name

Husband实体:@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)@PrimaryKeyJoinColumngetWife()@GenericGenerator(name = "Wife", strategy = "foreign", parameters = { @Parameter(name = "property", value = "husband") })Wife实体:@OneToOne(mappedBy = "wife", fetch = FetchType.LAZY)getHusband()
以上是hibernate中的配置。其中“optional=false”的配置时关键,否则即使配置了fetch策略为lazy,也无法做到在获取husband实体的时候延迟加载wife实体。optional的默认值是true,表示关联的实体可以为null。在一对一的延迟加载中,hibernate并非一定对需要延迟加载的实体生成一个动态代理对象,而是当被关联的实体确定不为null时,才会生成,否则直接将其置为null。所以问题就来了,对于两个通过主键关联的一对一实体,在获取到其中一个实体后,要判断与之关联的实体是否存在,则必须要再查询一次数据库才可以。这也就是为什么在设置了延迟加载策略后,hibernate还是立即发送了一次查询请求给数据库。

要解决一对一关系中的延迟加载,共有两种方法:一种就是上面提到的,把optional设置为false,即关联的实体一定不为null。这样一来,hibernate就会立即为配置延迟加载的实体生成一个动态代理类。

第二种方法就是通过外键来关联,即:

Husband:id,name, wife_id
Wife:id,name
其中husband_id与Husbande中的id关联

Husband实体:@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)@JoinColumn(name = "wife_id", , referencedColumnName = "id")getWife()Wife实体:@OneToOne(mappedBy = "wife", fetch = FetchType.LAZY)getHusband()
这样一来,直接可以通过husband中的wife_id的null与否来判断wife实体是否为null。


0 0
原创粉丝点击