Java OpenJPA快速抓取

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

我使用与WebSphere8.5捆绑在一起的OpenJPA2.3,并且必须从表中读取大量数据。我还必须获取很多与根实体的关系

Atm我正在使用CriteriaAPI创建搜索查询并选择实体。我用渴望的语言注释了所有的收藏。当我检查日志文件时,它会创建5个查询来获取所有子项。这就是我想要的方式。 问题是,在选择和停止1000个匹配实体之后,我必须在java中进行大量过滤。所以我想我应该指定fetch大小,并在得到1k结果后立即停止从db读取实体

如果引入FetchBatchSize设置,OpenJPA将为每个实体创建单个查询以加载子实体。(n+1问题)

我还尝试在查询中直接使用fetch-join语法,但没有成功。那么我做错了什么

我试过:

(一)

(二)

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");