Hibernate忽略“惰性"获取类型并立即加载属性 [英] Hibernate ignores 'lazy' fetch type and loads properties immediately

查看:142
本文介绍了Hibernate忽略“惰性"获取类型并立即加载属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Hibernate 5.2.5(如果重要的话,也可以使用kotlin和spring 4.3.5),并且我希望延迟加载类的某些字段.但是问题是所有字段都立即加载,我没有任何特殊的Hibernate设置,也没有使用Hibernate.initialize().

I use Hibernate 5.2.5 (also use kotlin and spring 4.3.5 if that matters) and I want some of the fields of my class to be loaded lazily. But the issue is that all fields are loaded immediately, I don't have any special Hibernate settings neither use Hibernate.initialize().

@Entity(name = "task")
@Table(name = "tasks")
@NamedQueries(
        NamedQuery(name = "task.findById", query = "SELECT t FROM task AS t WHERE t.id = :id")
)
class Task {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Int? = null

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "author_id", nullable = false)
    lateinit var author: User

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "task")
    var edit: TaskEdit? = null
}

这就是我的查询方式

TaskRepoImpl:

TaskRepoImpl:

override fun findById(id: Int): Task? {
    val task = getCurrentSession().createNamedQuery("task.findById", Task::class.java)
            .setParameter("id", id)
            .uniqueResult()
    return task
}

TaskService:

TaskService:

@Transactional
fun find(id: Int): Task? {
    return taskRepo.findById(id)
}

输出:

Hibernate: select task0_.id as id1_1_, task0_.author_id as author_i3_1_ from tasks task0_ where task0_.id=?
Hibernate: select user0_.id as id1_3_0_, user0_.enabled as enabled2_3_0_, user0_.name as name3_3_0_, user0_.password as password4_3_0_ from users user0_ where user0_.id=?
Hibernate: select taskedit0_.id as id1_0_0_, taskedit0_.task_id as task_id3_0_0_, taskedit0_.text as text2_0_0_ from task_edits taskedit0_ where taskedit0_.task_id=?

请告知我的代码有什么问题,以及如何使Hibernate加载属性变得懒惰?谢谢!

Please advice what's wrong with my code and how to make Hibernate load properties lazily? Thank you!

推荐答案

Hibernate无法代理您自己的对象. 对于此问题,至少有三个众所周知的解决方案: 最简单的方法是伪造一对多关系.这将起作用,因为延迟加载集合比延迟加载单个可为空的属性要容易得多,但是通常,如果使用复杂的JPQL/HQL查询,此解决方案将非常不便. 另一种是使用构建时字节码检测.有关更多详细信息,请阅读Hibernate文档:19.1.7.使用懒惰的属性获取.请记住,在这种情况下,必须将@LazyToOne(LazyToOneOption.NO_PROXY)批注添加到一对一关系以使其变得懒惰.仅将获取设置为LAZY是不够的. 最后一种解决方案是使用运行时字节码检测,但是它仅对在成熟的JEE环境中将Hibernate用作JPA提供程序的用户有效(在这种情况下,将"hibernate.ejb.use_class_enhancer"设置为true应该可以解决问题:实体管理器配置) )或将Hibernate与Spring配置为进行运行时编织(在某些较旧的应用服务器上可能很难实现).在这种情况下,还需要@LazyToOne(LazyToOneOption.NO_PROXY)批注.

Hibernate cannot proxy your own object. There are at least three well known solutions for this problem: The simplest one is to fake one-to-many relationship. This will work because lazy loading of collection is much easier then lazy loading of single nullable property but generally this solution is very inconvenient if you use complex JPQL/HQL queries. The other one is to use build time bytecode instrumentation. For more details please read Hibernate documentation: 19.1.7. Using lazy property fetching. Remember that in this case you have to add @LazyToOne(LazyToOneOption.NO_PROXY) annotation to one-to-one relationship to make it lazy. Setting fetch to LAZY is not enough. The last solution is to use runtime bytecode instrumentation but it will work only for those who use Hibernate as JPA provider in full-blown JEE environment (in such case setting "hibernate.ejb.use_class_enhancer" to true should do the trick: Entity Manager Configuration) or use Hibernate with Spring configured to do runtime weaving (this might be hard to achieve on some older application servers). In this case @LazyToOne(LazyToOneOption.NO_PROXY) annotation is also required.

 @Entity
public class Animal implements FieldHandled {
 private Person owner;
 private FieldHandler fieldHandler;

 @OneToOne(fetch = FetchType.LAZY, optional = true, mappedBy = "animal")
 @LazyToOne(LazyToOneOption.NO_PROXY)
 public Person getOwner() {
  if (fieldHandler != null) {
   return (Person) fieldHandler.readObject(this, "owner", owner);
  }
  return owner;
 }

 public void setOwner(Person owner) {
  if (fieldHandler != null) {
   this.owner = fieldHandler.writeObject(this, "owner", this.owner, owner);
   return;
  }
  this.owner = owner;
 }

 public FieldHandler getFieldHandler() {
  return fieldHandler;
 }

 public void setFieldHandler(FieldHandler fieldHandler) {
  this.fieldHandler = fieldHandler;
 }
}

您可以尝试以下方法: http://justonjava. blogspot.in/2010/09/lazy-to-one-and-one-to-many.html

Can you try this: http://justonjava.blogspot.in/2010/09/lazy-one-to-one-and-one-to-many.html

参考: 为什么延迟加载在一对一关联中不起作用?

这篇关于Hibernate忽略“惰性"获取类型并立即加载属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆