使用休眠 5.2 以流的形式查询结果

2022-09-02 22:16:58

从Hibernate 5.2开始,我们能够使用该方法,而不是我们想要获取大量数据。stream()scroll()

但是,当与一起使用时,我们能够将钩子挂接到检索过程中,并通过在处理对象后将其从持久上下文中逐出和/或不时清除整个会话来释放内存。scroll()ScrollableResults

我的问题:

  1. 现在,如果我们使用这种方法,幕后会发生什么?stream()
  2. 是否可以从持久上下文中逐出对象?
  3. 会话是否定期清除?
  4. 如何实现最佳内存消耗?
  5. 是否可以使用例如无国籍会话?
  6. 另外,如果我们在JPA属性处设置为某个数字(例如1000),那么如何将其与可滚动结果很好地结合在一起?hibernate.jdbc.fetch_size

答案 1

以下内容对我有用:

数据源配置.java

@Bean
public LocalSessionFactoryBean sessionFactory() {
    // Link your data source to your session factory
    ...
}

@Bean("hibernateTxManager")
public HibernateTransactionManager hibernateTxManager(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
    // Link your session factory to your transaction manager
    ...
}

MyServiceImpl.java

@Service
@Transactional(propagation = Propagation.REQUIRES_NEW, transactionManager = "hibernateTxManager", readOnly = true)
public class MyServiceImpl implements MyService {

    @Autowired
    private MyRepo myRepo;
    ...
    Stream<MyEntity> stream = myRepo.getStream();
    // Do your streaming and CLOSE the steam afterwards
    ...

MyRepoImpl.java

@Repository
@Transactional(propagation = Propagation.MANDATORY, transactionManager = "hibernateTxManager", readOnly = true)
public class MyRepoImpl implements MyRepo {

    @Autowired
    private SessionFactory sessionFactory;

    @Autowired
    private MyDataSource myDataSource;

    public Stream<MyEntity> getStream() {

        return sessionFactory.openStatelessSession(DataSourceUtils.getConnection(myDataSource))
            .createNativeQuery("my_query", MyEntity.class)
            .setReadOnly(true)
            .setFetchSize(1000)
            .stream();
    }
    ...

请记住,当您进行流式传输时,您实际上只需要在对象具体化点对内存保持谨慎。这确实是操作中唯一容易出现内存问题的部分。在我的例子中,我一次将流切块为1000个对象,使用gson序列化它们并立即将它们发送到JMS代理。垃圾回收器完成其余的工作。

值得注意的是,Spring的交易边界感知在最后关闭了与dB的连接,而不需要明确告知。


答案 2

休眠 ORM 用户指南指出:

在内部,stream() 的行为类似于 Query#scroll,基础结果由 ScrollableResults 提供支持。

您可以检查 的源代码,以确保定期清除会话或从持久性上下文中逐出对象。org.hibernate.query.internal.AbstractProducedQuery

正如我从评论中了解到的那样,这不是您的选择。我认为解决您的案件的干净方法是实施自己的方法。它可能与原始方法非常相似,只需在迭代期间替换为您自己的方法即可执行所需的操作(逐出对象或清除会话)。StatelessSessionstream()ScrollableResultsIterator


推荐