![](/img/trans.png)
[英]Spring Hibernate LazyInitializationException on @Transactional
[英]@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.