Java OpenJPA快速抓取
我使用与WebSphere8.5捆绑在一起的OpenJPA2.3,并且必须从表中读取大量数据。我还必须获取很多与根实体的关系 Atm我正在使用CriteriaAPI创建搜索查询并选择实体。我用渴望的语言注释了所有的收藏。当我检查日志文件时,它会创建5个查询来获取所有子项。这就是我想要的方式。 问题是,在选择和停止1000个匹配实体之后,我必须在java中进行大量过滤。所以我想我应该指定fetch大小,并在得到1k结果后立即停止从db读取实体 如果引入FetchBatchSize设置,OpenJPA将为每个实体创建单个查询以加载子实体。(n+1问题) 我还尝试在查询中直接使用fetch-join语法,但没有成功。那么我做错了什么 我试过: (一) (二)Java OpenJPA快速抓取,java,jpa-2.0,openjpa,Java,Jpa 2.0,Openjpa,我使用与WebSphere8.5捆绑在一起的OpenJPA2.3,并且必须从表中读取大量数据。我还必须获取很多与根实体的关系 Atm我正在使用CriteriaAPI创建搜索查询并选择实体。我用渴望的语言注释了所有的收藏。当我检查日志文件时,它会创建5个查询来获取所有子项。这就是我想要的方式。 问题是,在选择和停止1000个匹配实体之后,我必须在java中进行大量过滤。所以我想我应该指定fetch大小,并在得到1k结果后立即停止从db读取实体 如果引入FetchBatchSize设置,OpenJP
OpenJPAQuery kq=OpenJPAPersistence.cast(查询);
jdbfetchplan fetch=(jdbfetchplan)kq.getFetchPlan();
setFetchBatchSize(1000);
fetch.setResultSetType(仅限ResultSetType.FORWARD_);
fetch.setFetchDirection(FetchDirection.FORWARD);
fetch.setlrssiaelgorithm(lrssiaelgorithm.UNKNOWN);
实体:
@Entity
@Table(name = "CONTRACT")
public class Contract {
// omitted the other properties. The other relationships are annotated the same way
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "contract")
private List<Vehicle> vehicles= new ArrayList<Vehicle>();
@实体
@表(name=“合同”)
公共类合同{
//省略了其他属性。其他关系的注释方式相同
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL,mappedBy=“合同”)
私有列表车辆=新的ArrayList();
查询:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Contract> crit = cb.createQuery(Contract.class);
crit.distinct(true);
Root<Contract> r = crit.from(Contract.class);
// omited the where clause. In worst case I have a full table scan without any where clause. (the reason I need the batch size)
Fetch<Contract, Vehicle> fetchVehicles = r.fetch("vehicles", JoinType.LEFT); // I tried to work with a fetch join as well
TypedQuery<Contract> query = em.createQuery(crit);
// query.setHint("openjpa.FetchPlan.FetchBatchSize", FETCH_SIZE);
// query.setHint("openjpa.FetchPlan.ResultSetType", "SCROLL_INSENSITIVE");
OpenJPAQuery<?> kq = OpenJPAPersistence.cast(query);
JDBCFetchPlan fetch = (JDBCFetchPlan) kq.getFetchPlan();
fetch.setFetchBatchSize(FETCH_SIZE);
fetch.setResultSetType(ResultSetType.FORWARD_ONLY);
fetch.setFetchDirection(FetchDirection.FORWARD);
fetch.setLRSSizeAlgorithm(LRSSizeAlgorithm.UNKNOWN);
fetch.setEagerFetchMode(FetchMode.PARALLEL);
List<TPV> queryResult = query.getResultList();
// here begins the filtering and I stop as soon I have 1000 results
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery crit=cb.createQuery(Contract.class);
临界值不同(真);
根r=crit.from(Contract.class);
//省略where子句。在最坏的情况下,我有一个没有where子句的完整表扫描。(我需要批处理大小的原因)
Fetch fetchVehicles=r.Fetch(“vehicles”,JoinType.LEFT);//我也尝试使用Fetch连接
TypedQuery=em.createQuery(crit);
//setHint(“openjpa.FetchPlan.FetchBatchSize”,FETCH\u SIZE);
//setHint(“openjpa.FetchPlan.resultsetype”,“SCROLL_不敏感”);
OpenJPAQuery kq=OpenJPAPersistence.cast(查询);
jdbfetchplan fetch=(jdbfetchplan)kq.getFetchPlan();
setFetchBatchSize(获取大小);
fetch.setResultSetType(仅限ResultSetType.FORWARD_);
fetch.setFetchDirection(FetchDirection.FORWARD);
fetch.setlrssiaelgorithm(lrssiaelgorithm.UNKNOWN);
setFetchMode(FetchMode.PARALLEL);
List queryResult=query.getResultList();
//这里开始过滤,当我有1000个结果时,我就停止过滤
谢谢你的帮助!看看,你会发现渴望与你应该做的相反
正如我在评论中所说,EAGER
意味着JPA一次加载所有结果,因此不建议对大型结果集使用它。设置fetchBatchSize
会导致JPA延迟加载每x(在您的案例中为1000)个结果。因此,这实际上与使用@OneToMany(fetch=FetchType.lazy,…)的情况相同。
(也值得一试)
将fetchBatch
大小设置为一个小得多的数字(例如50)也会降低内存中保存的对象
也尝试
query.setHint("openjpa.FetchPlan.ResultSetType", "SCROLL_SENSITIVE");
似乎在我的场景中存在一些适用的bug。我找到了一个可扩展的解决方法 首先,我只选择ids(CriteriaAPI可以选择skalar值),并在那里应用批处理,因此,由于错误的抓取策略,我不再有n+1问题 在这之后,我用IN()语句批量选择实体,每次1000个,不受fetch batch size或max results的限制。因此,我没有遇到这个错误,OpenJPA为每个关系生成一个查询 因此,我对实体及其所有依赖项有大约6个查询
再次感谢thobens的帮助!您是否使用JPA注释实体?如果是,请您添加相关实体?是的,我会添加。请在一分钟内将其发布在编辑中。我展示了一个关系示例,当我处理批大小时,该关系不再急于加载。当然,因为
急于
意味着它会同时加载所有结果一次。(这对庞大的结果集来说是不好的)。设置fetchBatchSize
会导致JPA延迟加载每x(在您的案例中为1000)个结果。因此,这实际上与使用@OneToMany(fetch=FetchType.lazy,…)是一样的
这是有道理的。我的问题是我仍然需要孩子。我必须手动选择他们吗?敏感滚动类型对我有什么帮助?非常感谢!不,JPA会处理这个问题(如果您正确指定了查询,将其发布在这里会很有帮助)。我假设SCROLL_SENSITIVE允许您优化延迟重新加载实体,或者它可能会被忽略。您真的尝试过吗?已经没有工作了。我用我的查询更新了帖子。我的问题是此搜索功能必须获取所有子项。因此延迟加载不是一个真正的选项。我在序列化时会生成太多查询优化元素。我也将使用不同的结果集类型测试抓取。可能您在我的查询中发现了影响抓取的错误。可能我遇到了此错误:我需要抓取多个集合。
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Contract> crit = cb.createQuery(Contract.class);
crit.distinct(true);
Root<Contract> r = crit.from(Contract.class);
// omited the where clause. In worst case I have a full table scan without any where clause. (the reason I need the batch size)
Fetch<Contract, Vehicle> fetchVehicles = r.fetch("vehicles", JoinType.LEFT); // I tried to work with a fetch join as well
TypedQuery<Contract> query = em.createQuery(crit);
// query.setHint("openjpa.FetchPlan.FetchBatchSize", FETCH_SIZE);
// query.setHint("openjpa.FetchPlan.ResultSetType", "SCROLL_INSENSITIVE");
OpenJPAQuery<?> kq = OpenJPAPersistence.cast(query);
JDBCFetchPlan fetch = (JDBCFetchPlan) kq.getFetchPlan();
fetch.setFetchBatchSize(FETCH_SIZE);
fetch.setResultSetType(ResultSetType.FORWARD_ONLY);
fetch.setFetchDirection(FetchDirection.FORWARD);
fetch.setLRSSizeAlgorithm(LRSSizeAlgorithm.UNKNOWN);
fetch.setEagerFetchMode(FetchMode.PARALLEL);
List<TPV> queryResult = query.getResultList();
// here begins the filtering and I stop as soon I have 1000 results
query.setHint("openjpa.FetchPlan.ResultSetType", "SCROLL_SENSITIVE");