我只需要使用Hibernate读取MySQL数据库中表中的每一行,并根据它编写一个文件.但是有9000万行,它们非常大.所以看起来以下是合适的:
ScrollableResults results = session.createQuery("SELECT person FROM Person person")
.setReadOnly(true).setCacheable(false).scroll(ScrollMode.FORWARD_ONLY);
while (results.next())
storeInFile(results.get()[0]);
Run Code Online (Sandbox Code Playgroud)
问题是上面将尝试将所有9000万行加载到RAM中,然后再转到while循环...这将使OutOfMemoryError消除我的内存:Java堆空间异常:(.
所以我猜ScrollableResults不是我想要的?处理这个问题的正确方法是什么?我不介意这个while循环需要几天(好吧我不喜欢它).
我想处理这个问题的另一种方法是使用setFirstResult和setMaxResults迭代结果,只使用常规的Hibernate结果而不是ScrollableResults.这感觉就像它效率低下一样,当我在8900万行中调用setFirstResult时,它将开始花费一段可笑的时间......
更新:setFirstResult/setMaxResults不起作用,事实证明需要花费相当长的时间才能达到我所担心的偏移量.这里一定有解决方案!这不是一个很标准的程序吗?我愿意放弃Hibernate并使用JDBC或其他任何东西.
更新2:我提出的解决方案哪个工作正常,不是很好,基本上是以下形式:
select * from person where id > <offset> and <other_conditions> limit 1
Run Code Online (Sandbox Code Playgroud)
由于我有其他条件,即使是索引中的所有条件,它仍然没有我想要的那么快......所以仍然可以提供其他建议..
从Hibernate 5.2开始,我们可以使用该stream()
方法而不是scroll()
我们想要获取大量数据.
但是,当使用时scroll()
,ScrollableResults
我们能够通过在处理它之后从持久化上下文中驱逐对象和/或不时地清除整个会话来钩住检索过程并释放内存.
我的问题:
stream()
方法,幕后会发生什么?hibernate.jdbc.fetch_size
在JPA属性中设置了一些数字(例如1000),那么它如何与可滚动结果很好地结合?引起原因:org.hibernate.QueryException:无法解析 CAST 请求的类型:INT [ SELECT SUBSTRING(referenceComptable , 8, 14) AS seqNum, SUBSTRING(referenceComptable, 4,7) ASyearCegid, SUBSTRING(referenceComptable, 1,3) AS 期刊来自 com.dso.model.comptabilite.cegid.EtapeJudiciaireLnkFactureActesHonoraires WHERE dateCegidGenelated BETWEEN :date AND :dateYearIntervalDate ORDER BY CAST(seqNum AS INT), CAST(yearCegid AS INT), CAST(journal AS INT) ASC ]
HQL 查询: public ScrollableResultsretrieveSequenceNumberForCegidGenerate(){
StringBuilder queryBuilder = new StringBuilder(" SELECT SUBSTRING(referenceComptable , 8, 14) AS seqNum, SUBSTRING(referenceComptable, 4,7) AS yearCegid, SUBSTRING(referenceComptable, 1,3) AS journal")
.append(" FROM EtapeJudiciaireLnkFactureActesHonoraires ")
.append(" WHERE dateCegidGenerated BETWEEN :date AND :dateYearIntervalDate ")
.append(" ORDER BY CAST(seqNum AS INT), …
Run Code Online (Sandbox Code Playgroud) 我是 JPA 的新手,我想知道是否可以从结果集中流式传输数据,我的意思是我不想等待执行查询来开始处理第一个结果,例如在这种情况下一批。
是否有可能使用 JPA API 或任何社区采用的解决方法?最终使用 JPA 实现的功能?
我正在尝试使用Hibernate从表中检索大约1亿行.我有一个持久化的实体项目,其中包含一个费用集合(另一个持久化实体).鉴于我将迭代结果并访问每个对象的费用,我想急切地获取费用以避免n + 1问题.
我还要提一下,我想将它加入另一个名为Provider的表(一对一映射但没有外键).我试过了:
String query = "select new " + Order.class.getName()
+ "(i, p) from Item i left join fetch i.fees f, Provider p where "
+ "p.factoryId=i.factoryId and p.factoryRef=i.factoryRef";
return session.createQuery(query).scroll();
Run Code Online (Sandbox Code Playgroud)
我的Order类包含Provider字段和Item字段.我收到此错误:
引起:org.hibernate.QueryException:查询指定的连接提取,但选择列表中不存在获取的关联的所有者
我想最终得到一个可滚动的Order列表,其中包含Item(收取费用)和Provider.
我有以下查询,当我尝试使用 hibernate 执行它时,出现以下异常:
org.hibernate.exception.SQLGrammarException: 无法使用滚动执行查询。
在我的代码中,我滚动了 FORWARD_ONLY。任何人都可以提供一个完美的解决方案。
select * from (SELECT account_no AS accountno,rownum r FROM sc_dcm_postpaid_index WHERE groupid = 'SBG-2012'
and concat(trim(TO_CHAR(bill_date,'MONTH')),concat('-',TO_CHAR(bill_date,'YY')))='JUNE-12'
AND ROWID IN (SELECT MAX(ROWID) AS row_no ; FROM sc_dcm_postpaid_index
WHERE groupid= 'SBG-2012' and concat(trim(TO_CHAR(bill_date,'MONTH')),concat('-',TO_CHAR(bill_date,'YY')))='JUNE-12'
GROUP BY account_no HAVING COUNT (account_no) >= 1 ) ORDER BY account_no)where r >= 11 and r <= 21..
Run Code Online (Sandbox Code Playgroud)
此外,当我将查询更改为
SELECT account_no AS accountno,rownum r FROM sc_dcm_postpaid_index WHERE rownum >= 11 and rownum <= 21 groupid = 'SBG-2012'
and concat(trim(TO_CHAR(bill_date,'MONTH')),concat('-',TO_CHAR(bill_date,'YY')))='JUNE-12'
AND ROWID …
Run Code Online (Sandbox Code Playgroud) 我想使用可滚动的结果集,所以当我使用两行代码时:
rs.setFetchDirection(ResultSet.TYPE_SCROLL_SENSITIVE);
rs.absolute(12);
Run Code Online (Sandbox Code Playgroud)
在我的DAOimpl中,我得到例外,plz帮助解决它们,谢谢提前.
import oracle.jdbc.OracleTypes;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Component;
@Component
public class MyDAOimpl extends JdbcDaoSupport implements
MyDAO {
public List<User> getList(final String where) throws Exception {
return (List) getJdbcTemplate().execute(
"{call PKG_USER.getUser(?,?)}",
new CallableStatementCallback() {
public Object doInCallableStatement(CallableStatement cs)
throws SQLException {
cs.setString(1, where);
cs.registerOutParameter(2, OracleTypes.CURSOR);
cs.execute();
ResultSet rs = (ResultSet) cs.getObject(6);
rs.setFetchDirection(ResultSet.TYPE_SCROLL_SENSITIVE);
rs.absolute(12);
List<User> list = new ArrayList<User>();
while (rs.next()) {
User user = new User(
rs.getString(1),
rs.getString(2),
rs.getString(3));
list.add(user);
}
return list;
}
});
}
} …
Run Code Online (Sandbox Code Playgroud) 我有一个基于Criteria的查询,其中包含以下分组:
Projections.projectionList()
.add(Property.forName("xyz").group()));
Run Code Online (Sandbox Code Playgroud)
生成的SQL是(专有的,如此清理):
select this_.XYZ as y0_ from FOO.BAR this_ WHERE [long where clause]
group by this_.XYZ
Run Code Online (Sandbox Code Playgroud)
现在,从概念上讲,我想用count(*)包装查询结果,以便数据永远不会从数据库返回,只是计数.像这样:
select count(*) from (
select this_.XYZ as y0_ from FOO.BAR this_ WHERE [long where clause]
group by this_.XYZ
)
Run Code Online (Sandbox Code Playgroud)
可能有数千行我不需要,而且我对高性能感兴趣,所以我不希望这些数据来自网络.
我的基于标准的搜索有很多条件.我无法现实地重建它,所以我真的需要坚持使用Criteria.
当然,添加rowCount或count("xyz")并没有帮助,因为它只为每行报告1.
我正在这样做以获得计数:
ScrollableResults scroll = criteria.scroll();
scroll.last();
int count = scroll.getRowNumber();
Run Code Online (Sandbox Code Playgroud)
它有效,但是需要花费很长时间才能重新计算(如果重要的话,在Oracle上).
我可以做我提出的建议吗?