OpenJPA渴望获取

时间:2014-04-03 14:56:08

标签: java jpa-2.0 openjpa

我使用与WebSphere 8.5捆绑在一起的OpenJPA 2.3,我必须从表中读取大量数据。我还必须与根实体取得很多关系。

Atm我正在使用条件API来创建搜索查询并选择实体。我用EAGER注释了所有收藏品。当我检查日志文件时,它会创建5个查询以获取所有子项。这就是我想要的方式。 问题是我必须在选择后在java中过滤很多并在1000个匹配实体后停止。所以我想我会指定获取大小并在我获得1k结果后立即停止从数据库中读取实体。

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

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

我试过了:

1)

    query.setHint("openjpa.FetchPlan.FetchBatchSize", 1000);
    query.setHint("openjpa.FetchPlan.ResultSetType", "SCROLL_INSENSITIVE"); 

2)

        OpenJPAQuery<?> kq = OpenJPAPersistence.cast(query);
        JDBCFetchPlan fetch = (JDBCFetchPlan) kq.getFetchPlan();
        fetch.setFetchBatchSize(1000);
        fetch.setResultSetType(ResultSetType.FORWARD_ONLY);
        fetch.setFetchDirection(FetchDirection.FORWARD);
        fetch.setLRSSizeAlgorithm(LRSSizeAlgorithm.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>();

查询:

        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

感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

看看how to deal with large result sets,你会发现EAGER与你应该做的相反。

正如我在评论中所述,EAGER表示JPA一次加载所有结果,因此不建议用于大型结果集。设置fetchBatchSize会导致JPA延迟加载每个x(在您的情况下为1000)结果。所以它实际上就像你使用@OneToMany(fetch = FetchType.LAZY, ...)(也值得一试)

一样

fetchBatch大小设置为更低的数字(例如50)也会降低内存中保存的对象。

也可以尝试

query.setHint("openjpa.FetchPlan.ResultSetType", "SCROLL_SENSITIVE"); 

答案 1 :(得分:0)

似乎有一些Bugs提交适用于我的场景。我发现了一种可以很好地扩展的解决方法。

首先,我只选择ID(Criteria API可以选择标量值),然后在那里应用批处理。因此,由于错误的提取策略,我没有n + 1问题。

在此之后,我使用IN()语句选择我的实体,批量为1000,而不限制获取批量大小或最大结果。所以我没有碰到这个bug,OpenJPA为每个关系生成一个查询。

所以我对该实体及其所有依赖项有大约6个查询。

再次感谢thobens的帮助!