繁体   English   中英

Spring Boot + Hibernate + Thymeleaf 延迟加载异常

[英]Spring Boot + Hibernate + Thymeleaf Lazy loading exception

我正在开发 Spring Boot web 服务,但遇到了问题,不知道如何解决(我已经尝试了很多天......)

在我的数据库中,我有 AB 和 C 三个表,关系是 A 一对多 B,B 一对多 C。

In my spring boot controller, I need to have a findById() function for table A, when I call this endpoint, the data in A, B and C should be retrieved accordingly.

表 C 中的数据量很大,大约有 16K 条记录。

这就是背景。

现在,如果我为表 A 调用 findById(),则表 A 内的数据会完美加载,这很好,但是,由于延迟加载异常,我无法从 B 和 C 获取数据。

为了解决这个问题,我将 fetch 类型更改为 EAGER fetch。 但是,获取数据需要很长时间,这真的很糟糕,(我可以说没有无限循环,我猜只是因为数据量很大,我调试时通常需要40秒才能得到结果)

因此,我尝试了其他一些东西。 由于我意识到这个项目我有多个数据库连接,所以我添加了另一个注释 @Transanctional("transactionName") 来限制服务和存储库只扫描特定事务中的数据。 它有效!

然而!!!

这个 controller 如下所示:

@Transactional("name")
public String findDataInTableAById(@PathVariable("id") Integer id, Model model)
    {
         ModelA a = tableAService.findById(id);
         model.add("dataInThymeleaf", a);
         return "/path/page.html"
    }

当我在 ModelA 上设置断点时 a = tableAService.findById(id); 我绝对可以在调试控制台中完美地看到所有数据加载。 但是,当我将它提供给我的前端(Thymeleaf)时,它又给了我一个延迟加载异常。 我做了一些研究,我想这是因为 session 在我将其传递给 Thymeleaf 之前已经关闭。

想知道是否有人遇到同样的问题以及如何解决?

TL;DR - 尝试通过访问标记为延迟的字段来强制延迟加载在您的方法中发生。 这有点像a.getB().size(); a.getB().getC().size(); a.getB().size(); a.getB().getC().size(); model.add()行之前。 这将在事务中加载惰性数据并避免异常,但我很确定它不会让事情变得更快。 原因如下:

首先,这纯属JPA的事情,Thymeleaf与问题无关,而Spring本身,如果使用不当可能也不会。

正如您已经提到的,这是一个 LAZY 与 EAGER 的问题。 延迟加载意味着依赖实体( @OneToMany或其他)仅在需要时在访问它们时加载,而不是在查询时加载。 有几件重要的事情需要注意/理解:

  • 总而言之,延迟加载实际上(略微)急切加载要慢。 这将使您的初始查询更快地完成,因此您将更快地获得一些数据,但是如果您随后需要延迟加载相关条目,则总加载时间将比您直接加载它们时多一点.

  • 因此,延迟加载仅在您很有可能某些代码执行中根本不需要这些条目时才有意义。 如果您以后肯定需要它们,请不要使用延迟加载。

  • 另一个重要的限制 - 延迟加载只能发生在加载父实体的同一事务/会话中。 事务提交/回滚后,您不能再从该结果列表中加载任何数据。

就您而言,最后一点是问题所在。 您的 GUI/模板引擎正在尝试访问延迟加载的列表,但是当他们访问它时,session 已关闭。

除了在 session 打开时实际加载数据外,没有其他办法,这意味着在您上面引用的方法内。 从技术上讲,延迟加载或急切加载并不重要,但是如果延迟加载,则不会获得任何性能改进。

还有一件事让我感到惊讶 - 你说你的表 C 是“巨大的”并且有 16K 条记录。 如果你的意思是 16000,那么这不算什么。 一个巨大的表是如果它有 160 亿个条目。 1600 万也很大,但不是很大。 当前硬件上的任何数据库都应几乎立即处理任何低于几百万个条目的内容。

这让我觉得你的问题可能出在其他地方。 如果你需要 40 秒来对这么小规模的数据运行一次查询,那么无论是惰性加载还是急切加载,这都是不正常的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM