Java 使用Hibernate 5.2将查询结果作为流
自Hibernate 5.2以来,如果我们想要获取大量数据,我们可以使用Java 使用Hibernate 5.2将查询结果作为流,java,hibernate,jpa,stream,scrollableresults,Java,Hibernate,Jpa,Stream,Scrollableresults,自Hibernate 5.2以来,如果我们想要获取大量数据,我们可以使用stream()方法而不是scroll() 但是,当将scroll()与ScrollableResults一起使用时,我们可以通过在处理对象后将其从持久性上下文中逐出和/或不时清除整个会话,来连接检索过程并释放内存 我的问题是: 现在,如果我们使用stream()方法,那么幕后会发生什么 是否可以从持久性上下文中逐出对象 会话是否定期清除 如何实现最佳内存消耗 是否可以使用无状态会话 另外,如果我们在JPA属性中将hiber
stream()
方法而不是scroll()
但是,当将scroll()
与ScrollableResults
一起使用时,我们可以通过在处理对象后将其从持久性上下文中逐出和/或不时清除整个会话,来连接检索过程并释放内存
我的问题是:
stream()
方法,那么幕后会发生什么李>
hibernate.jdbc.fetch_size
设置为某个数字(例如1000),那么如何将其与可滚动结果很好地结合起来呢以下是我的作品: DataSourceConfig.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
...
}
@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
...
@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();
}
...
MyServiceImpl.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
...
}
@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
...
@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();
}
...
@服务
@事务性(propagation=propagation.REQUIRES_NEW,transactionManager=“hibernateTxManager”,readOnly=true)
公共类MyServiceImpl实现了MyService{
@自动连线
私人MyRepo MyRepo;
...
Stream=myRepo.getStream();
//做你的流和关闭蒸汽后
...
MyRepoImpl.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
...
}
@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
...
@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();
}
...
@存储库
@事务性(propagation=propagation.MANDATORY,transactionManager=“hibernateTxManager”,readOnly=true)
public类myrepimpl实现MyRepo{
@自动连线
私人会话工厂会话工厂;
@自动连线
私有MyDataSource MyDataSource;
公共流getStream(){
返回sessionFactory.openStatelessSession(DataSourceUtils.getConnection(myDataSource))
.createNativeQuery(“我的查询”,MyEntity.class)
.setReadOnly(真)
.setFetchSize(1000)
.stream();
}
...
请记住,流式处理时,只需在对象具体化时小心内存。这确实是操作中唯一容易出现内存问题的部分。在我的例子中,我一次将1000个对象分块处理流,用gson序列化它们,并立即将它们发送给JMS代理。垃圾收集器会这样做其余的都是
值得注意的是,Spring的事务边界感知最终关闭了与dB的连接,而无需明确告知。Hibernate ORM用户指南
在内部,stream()的行为类似于查询#滚动,底层结果由ScrollableResults支持
您可以检查org.hibernate.query.internal.AbstractProducedQuery,以确保您有责任定期清除会话或从持久上下文中逐出对象
我从评论中了解到,
无状态会话
不适合您。我认为解决您的问题的干净方法是实现您自己的stream()
方法。它可能与原始方法非常相似,只需将ScrollableResultsIterator
替换为您自己的方法即可(逐出对象或清除会话)在迭代过程中。您是否愿意与我们分享您是如何测量内存占用的?我们还注意到,您使用了本机查询,而在我们的情况下,本机查询不是一个选项。说我们也不能使用无状态会话。我通过大量的性能测试和分析工具测量了内存占用。最后,我流式处理了6500万次n条记录(获取大小为1000条,然后具体化为每个JMS消息1000条记录)直接进入安慰。如果您需要这方面的代码,我可以添加它。如果您不使用本机查询或无状态会话,我建议您向hibernate添加一个提示,告诉它cacheable=false。有什么原因不能使用无状态会话吗?我们的代码存在于Spring事务边界内,并且与其他会话的操作方式相同我们将执行的其他读取。在我们的应用程序中,实体管理器已禁用二级缓存。我们不能使用无状态会话的另一个原因是我们有动态条件查询。只要在事务后连接关闭,并且您使用的是最小缓存,您就应该可以。@wild\u nothing:您能通知我们吗您使用的是哪一个数据库?因为使用无状态会话
会产生不同,而且用户需要定期清除会话等。我不太确定可滚动结果
或流()的附加值是多少
在hibernate中。我还阅读了以下文章:,这是促使我调查此问题的文章。与此主题相关的有趣文章:相关hibernate JIRA问题: