是否使用Session.buildLockRequest()将实体重新附加到EntityManager是一个实用的解决方案?

时间:2016-02-25 08:19:46

标签: hibernate jpa lazy-loading entitymanager hibernate-session

我的问题相对简单:

我有一个带有许多延迟加载集的实体,我不需要一直使用它。现在我不想急切地加载所有内容,也不想要有几个不同的getSlimEntity(),getFullEntity(),getEntityForSpecialOccasion()方法。

我想做的是默认使用'slim'版本然后根据需要加载懒惰的东西。该需求可能源于更改显示“任务”实体的网页上的选项卡。新选项卡应显示任务的历史记录。但是,这个标签并不经常使用,所以我不急切地想要这些数据。

解决方案应该尽可能少地在数据库上工作,因为数据库性能这对我们来说是一个问题。

我想出的一个可能的解决方案是使用Session.buildLockRequest()将任务“重新附加”到EntityManager,并在我需要的Set上调用Hibernate.initialize()。它看起来像这样:

public Set<HistoryEntry> getHistory(Task task) {

    Session session = manager.unwrap(Session.class);
    session.buildLockRequest(LockOptions.NONE).lock(task);

    Hibernate.initialize(task.getHistory());

    return task.getHistory();
}

这是一个纤薄且相对易于理解的解决方案,数据库也没有更新或任何内容,只是查询有问题的HistoryEntries。

现在我的问题:这个解决方案可以使用吗?它是否会造成我看不到的任何问题?通过调用buildLockRequest实际发生了什么?此外,当多个用户查看同一任务时是否会出现问题?

//编辑:正如所指出的,此解决方案使用可能与其他持久性提供程序不兼容的Hibernate特定调用,例如EclipseLink或OpenJPA。由于这个项目只是内部的,所以这应该不是问题。

1 个答案:

答案 0 :(得分:2)

我不确定是否使用LockRequest#lock()将对象重新连接到会话(顺便说一下,behaves strangely,因为它没有进行任何版本检查或同步更改)是一个好主意。在你的情况下,它似乎是一个合适的解决方案,但它看起来像一个副作用,我不会依赖这个功能。

另一件事是 - 在使用Hibernate时谈论JPA特定电话是不好的,正如MWiesner在评论中已经指出的那样。

你有很多选择:

  1. 如果您知道在从数据库检索时如何使用对象 - 请使用entity graphs
  2. 您只需查询检索所有Histories传递的实体。
  3. 如果您知道无法更改传递的对象,则只需通过EntityManager#merge将其重新附加到持久性上下文。
  4. 为什么不选择上述之一?