【发布时间】:2014-05-15 12:06:59
【问题描述】:
我使用与 WebSphere 8.5 捆绑在一起的 OpenJPA 2.3,我必须从表中读取大量数据。我还必须获取与根实体的很多关系。
Atm 我正在使用标准 API 创建搜索查询并选择实体。我用 EAGER 注释了所有集合。当我检查日志文件时,它会创建 5 个查询来获取所有子项。这就是我想要的方式。 问题是我必须在选择后在 java 中过滤很多,并在 1000 个匹配实体后停止。所以我想我指定了 fetch 大小并在我得到 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
感谢您的帮助!
【问题讨论】:
-
您使用 JPA 注释实体吗?如果有,能否请您添加相关实体?
-
是的,我愿意。一分钟后将其发布到编辑中。
-
我展示了一个关系示例,当我使用批量大小时,它不再急切加载。
-
当然可以,因为
EAGER意味着它会一次加载所有结果。 (无论如何这对于巨大的结果集都是不利的)。设置fetchBatchSize会导致 JPA 延迟加载每个 x(在您的情况下为 1000)结果。所以它实际上与使用@OneToMany(fetch = FetchType.LAZY, ...)相同