11

我遇到了一个问题,JPA 试图在我不想要的时候延迟加载我的数据。基本上发生的事情是我正在使用服务来检索一些数据,当我将该数据解析为 JSON 时,JSON 库正在触发休眠以尝试延迟加载数据。有没有办法阻止这种情况?我在下面给出了一个例子。

// Web Controller method
public String getEmployeesByQuery(String query) {

    Gson gson = new Gson();
    List<Employee> employees = employeeService.findEmployeesByQuery(query);

    // Here is where the problem is occurring - the gson.toJSON() method is (I imagine)
    // using my getters to format the JSON output, which is triggering hibernate to
    // try and lazily load my data...
    return gson.toJSON(employees);
}

是否可以将 JPA/hibernate 设置为不尝试延迟加载数据?

更新:我意识到您可以使用 FetchType.EAGER - 但是如果我不想急切加载该数据怎么办?我只是想阻止休眠尝试检索更多数据——我已经有了我想要的数据。现在,每当我尝试访问 get() 方法时,hibernate 都会抛出“没有会话或会话已关闭”错误,这是有道理的,因为我的事务已经从我的服务提交。

谢谢!

4

8 回答 8

6

有几种选择:

  • 如果您总是需要急切地加载您的收藏,您可以fetch = FetchType.EAGER在映射中指定,如其他答案中所建议的那样。

  • 否则,您可以为特定查询启用即时获取:

    • 通过JOIN FETCH在 HQL/JPQL 查询中使用子句:

      SELECT e FROM Employee e JOIN FETCH e.children WHERE ...
      
    • 通过使用获取配置文件Session(在 JPA 中,您可以通过访问 Hibernate em.unwrap(Session.class)
于 2011-01-26T15:01:32.463 回答
3

你真的有两个选择:

  1. 您可以将数据从员工复制到没有被休眠代理的数据。
  2. 看看是否有办法不让toJSON库反映整个对象图。我知道一些 JSON 库只允许您将对象的某些属性序列化为 JSON。

我个人认为如果你的库只使用反射,#1 会更容易。

于 2011-01-26T15:47:18.367 回答
2

正如其他人所说,这不是 JPA/hibernate 的问题,而是您使用的 json 序列化库的问题。您应该指示gson 排除您不想遍历的属性。

于 2011-01-26T20:04:49.393 回答
1

是的:

@*ToMany(fetch=FetchType.EAGER)
于 2011-01-26T14:44:32.333 回答
1

我建议您制作要在事务之外使用的实体的获取副本。这样,延迟加载将在事务中发生,您可以向 Gson 传递一个普通的,而不是增强的 POJO。

您可以使用Doozer来执行此操作。它非常灵活,通过一些配置(读起来你会松散配置它),你甚至可以只检索部分你想发送给 Gson 的数据。

于 2011-01-26T15:41:12.003 回答
0

您可以随时将fetch属性更改为FetchType.EAGER,但如果您的事务具有正确的范围,也值得考虑。如果在事务中访问集合,它们将被正确加载。

于 2011-01-26T14:47:42.500 回答
0

您的问题是您正在序列化数据。我们在使用 Flex 和 JPA/Hibernate 时遇到了同样的问题。诀窍是,取决于你想要破坏多少东西,要么

  1. 改变你的数据模型,不要追逐你不想要的数据。
  2. 将您想要的数据复制到某种无需担心关系的 DTO 中。
  3. 假设您使用的是 Hibernate,请添加 Session-in-view 过滤器......类似这样,它会在您序列化整个数据库时保持会话打开。;)

选项一是我们为我们所做的第一个大型项目所做的,但它破坏了我们为任何通用用途而拥有的数据访问库。从那时起,我们更倾向于选择二。

YMMV

于 2011-01-26T16:39:08.607 回答
0

简单直接的做法是创建新的数据类(类似于 DTO)使用 Hibernate.isInitialized() 来检查对象是否由 hibernate 初始化。我正在检查 gson 是否可以覆盖任何内容。如果我发现任何新内容,我会在这里发布。

于 2011-07-27T13:24:11.610 回答