我有以下问题。据我了解@Transactional
注释应该使 session 保持 Activity 状态,从而能够延迟获取子实体,而无需执行特定的联接查询。
我遇到以下情况,我不明白为什么我仍然得到 LazyInitializationException
.
我的应用程序运行解析器,以便为各种 Controller 服务提供已解析的对象,以便可以直接使用它。
所述解析器拦截请求中的 header ,并使用它的值尝试查询数据库以获取对象。现在所讨论的对象非常简单,尽管它有两个子实体的列表,但它的作用却很简单。
为了执行解析操作,我使用了一项额外的服务,其中我基本上包装了一些 JpaRepository
方法。完整内容如下:
@Service
public class AppClientServiceImpl implements AppClientService {
private static final Logger LOGGER = LoggerFactory.getLogger(AppClientServiceImpl.class.getCanonicalName());
private final AppClientRepository repository;
@Autowired
public AppClientServiceImpl(AppClientRepository repository) {
this.repository = repository;
}
@Override
@Transactional(readOnly = true)
public AppClient getByAppClientId(final String appClientId) {
LOGGER.debug("Attempting to retrieve appClient with id:: {}", appClientId);
return repository.findByAppClientId(appClientId);
}
@Override
@Transactional
public void saveAndFlush(final AppClient appClient) {
LOGGER.debug("Attempting to save/update appClient:: {}", appClient);
repository.saveAndFlush(appClient);
}
}
如您所见,这两种方法都注释为 @Transactional
这意味着应该在该方法的上下文中保持 session 处于 Activity 状态。
现在,我的主要问题如下:
1) 使用我在该级别上看到的调试器 getByAppClientId
包含延迟加载的子实体的列表已得到很好的解析。
2) 在解析器本身上,从委托(delegate)方法接收到对象时,由于LazyInitializationException
而无法评估列表。 .
3) 最后是最终 Controller 服务方法,也标记为 @Transactional
,与上面相同的情况发生意味着这最终无法完成它的工作(因为它正在执行未能初始化的列表的获取。
基于上述所有内容,我想知道处理此问题的最佳方法是什么。这一次我不想使用急切获取类型,并且我也想避免使用获取查询。还将我的解析器标记为 @Transactional
因此,在那里保持 session 开放也是不可能的。
我认为自从 @Transactional
将使 session 保持打开状态,从而使最终服务方法能够获取子实体列表。看来事实并非如此。
基于上述所有内容,我似乎需要一种方法来调用最终的服务方法(需要手头的列表)以某种方式获取它。
处理这个问题的最佳方法是什么?我在这里阅读了很多帖子,但我无法弄清楚 Spring boot 2.0 和 hibernate 5 中哪种方法是最受接受的方法。
更新:
似乎用以下内容注释子实体:
@Fetch(FetchMode.SELECT) @LazyCollection(LazyCollectionOption.TRUE)
解决了问题,但我仍然不知道这是否是最好的方法。
最佳答案
您可以通过调试来初始化集合。调试器通常通过使用触发初始化的集合方法以特殊方式表示集合,因此这可能是它在调试期间似乎工作正常的原因。我想解析器在 getByAppClientId 的范围之外运行?此时 session 已关闭,这就是您看到异常的原因。
我创建了Blaze-Persistence Entity Views正是针对该用例。您本质上将 JPA 实体的 DTO 定义为接口(interface)并将它们应用于查询。它支持映射嵌套 DTO、集合等,基本上是您期望的所有内容,最重要的是,它将提高您的查询性能,因为它将生成仅获取 DTO 实际需要的数据的查询。
您的示例的实体 View 可能如下所示
@EntityView(AppClient.class)
interface AppClientDto {
String getName();
}
查询可能如下所示
List<AppClientDto> dtos = entityViewManager.applySetting(
EntityViewSetting.create(AppClientDto.class),
criteriaBuilderFactory.create(em, AppClient.class)
).getResultList();
关于java - @Transactional 注解 Spring boot 2.0 和 hibernate LazyInitializationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50785611/