繁体   English   中英

@Transactional注释Spring Boot 2.0和休眠LazyInitializationException

[英]@Transactional annotation Spring boot 2.0 and hibernate LazyInitializationException

我有以下问题。 据我了解,@ @Transactional批注应该保持会话有效,从而无需执行特定的联接查询就可以延迟获取子实体。

在以下情况下,我不理解为什么我仍然收到LazyInitializationException

我的应用程序运行一个解析程序,以便为各种控制器服务提供一个已解析的对象,以便可以直接使用它。

所述解析器从请求中截取标头,并使用其值尝试查询db以便获取对象。 现在,有问题的对象非常简单,尽管它有两个子实体的列表,但是它正在执行操作。

为了执行解析操作,我使用了一个额外的服务,其中基本上包装了一些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这意味着应当在该方法的上下文@Transactional会话保持活动状态。

现在,我的主要问题如下:

1)使用调试器,即使在getByAppClientId级别上,我也看到延迟加载的子实体上包含的列表已得到很好的解决。

2)在解析器本身上,从委托方法接收到对象的情况下,由于LazyInitializationException导致无法评估列表。

3)最后,在最后一个控制器服务方法(也被标记为@Transactional ,与上述相同,这意味着它最终无法完成工作(因为它正在执行未能初始化的列表的获取)。

基于上述所有内容,我想知道什么是处理此问题的最佳方法。 一次我不想使用Eager访存类型,并且我也想避免使用访存查询。 还将我的解析器标记为@Transactional从而使会话也在那里保持打开也是不可能的。

我虽然这样,因为@Transactional可以使会话保持打开状态,从而使最终的服务方法能够获取子实体列表。 似乎并非如此。

基于以上所有内容,似乎我需要一种用于最终服务方法的方法,该方法可以通过某种方式获取调用(需要手头的列表)。

处理此问题的最佳方法是什么? 我在这里已经读了很多文章,但是我无法确定哪种是Spring Boot 2.0和Hibernate 5以来最受欢迎的方法。

更新:

似乎用以下内容注释了子实体:

@Fetch(FetchMode.SELECT)@LazyCollection(LazyCollectionOption.TRUE)

解决了问题,但我仍然不知道这是否是最佳方法。

您可以通过调试初始化集合。 调试器通常使用触发初始化的收集方法以特殊的方式表示收集,因此这可能是它在调试期间似乎可以正常工作的原因。 我想解析器在getByAppClientId范围之外运行? 届时会话已关闭,这就是您看到异常的原因。

我正是为该用例创建了Blaze-Persistence实体视图 您实际上将JPA实体的DTO定义为接口,并将其应用于查询。 它支持映射嵌套的DTO,集合等,本质上是您期望的所有内容,此外,它还将提高查询性能,因为它将生成查询,仅提取DTO实际需要的数据。

您的示例的实体视图可能如下所示

@EntityView(AppClient.class)
interface AppClientDto {
  String getName();
}

查询可能看起来像这样

List<AppClientDto> dtos = entityViewManager.applySetting(
  EntityViewSetting.create(AppClientDto.class),
  criteriaBuilderFactory.create(em, AppClient.class)
).getResultList();

暂无
暂无

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

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