一、报错信息
Cannot evaluate com.golaxy.entity.ht.HtGameMatch
HibernateProxyJDtPJ0Dx.toString()
- 场景:
- 在使用SpringbootTest类操作Repository访问数据库时报错,具体方法:
getOne()
- 以及通常发生在试图访问一个已经被 Hibernate 关闭的 Session 或 EntityManager 的持久化对象或集合时。
二、原因
- 这个问题的根源是 Hibernate 的延迟加载(Lazy Loading)策略。
- Hibernate 使用这种策略来提高应用程序的性能:当你从数据库加载一个实体时,Hibernate 不会立即加载它的所有相关实体,而是等到你真正需要它们的时候再加载。
- 这种策略在大多数情况下都能提高性能,但是如果你在 Session 或 EntityManager 关闭后再试图访问这些延迟加载的实体,就会抛出
LazyInitializationException
。
具体到本处,使用getOne方法从数据库加载时,并不会立即从数据库加载实体对象,只会返回一个代理类。只有当首次访问这个代理对象的非主键属性时,Hibernate才会从数据库中加载实体。而这个时候由于连接已经关闭,所以抛出异常
三、解决方法:
- 使用 Hibernate 的 initialize() 方法:
可以在 Session 或 EntityManager 关闭之前,使用 Hibernate 的 Hibernate.initialize(yourEntity) 方法来初始化你的实体。这会立即加载实体,而不是等到访问它的时候再加载。Hibernate.initialize(gameMatch.getGame());
- 使用findById()方法代替getOne()
findById()不是懒加载方法,所以直接返回对象
Optional<HtGameMatch> optional = htGameRepository.findById((id);
if (optional.isPresent()) {
Entity one = optional.get();
Long id = one.getId();
xxService.updatexxx(List.of(one));
}
- 在访问实体的非主键属性之前,确保 Session 或 EntityManager 仍然打开:你可以更改你的代码结构,以确保你在正确的时机访问你的实体。