Java 用于检索复杂实体的高效JPQL查询
我是JPA/JPQL的新手,如果这个问题不太清楚,请原谅 我试图找到一个有效的JQPL查询,以便获得复杂对象的所有记录 即,由多个表表示,具有多个一对多关系-参见下面的简化示例:Java 用于检索复杂实体的高效JPQL查询,java,sql,hibernate,jpa,jpql,Java,Sql,Hibernate,Jpa,Jpql,我是JPA/JPQL的新手,如果这个问题不太清楚,请原谅 我试图找到一个有效的JQPL查询,以便获得复杂对象的所有记录 即,由多个表表示,具有多个一对多关系-参见下面的简化示例: class ComplexObject { private Set< SubOject1> so1 ... ..... @OneToMany(fetch = FetchType.LAZY) public Set< SubOject1>... } class Su
class ComplexObject {
private Set< SubOject1> so1 ...
.....
@OneToMany(fetch = FetchType.LAZY)
public Set< SubOject1>...
}
class SubObject1 {
private Set< SubOject2> so2 ...
.....
@OneToMany(fetch = FetchType.LAZY)
public Set< SubOject2>...
}
查询在无状态会话上运行,以获取数据库中当前数据的实际快照,该快照与实体管理器分离,因此使用左连接获取
不幸的是,我遇到了两个问题:
由于复杂对象包含多个so1实例,并且每个so1实例都包含多个so2实例,因此对SQL查询的底层转换会在所有表联接的乘积的每行生成一个特定的select查询,这是一个非常浪费的解决方案。有没有办法减少内部select查询的数量?这似乎是可怕的N+1查询问题
JPQL查询在所有表联接的乘积上的每个内部SQL查询返回一个ComplexObject实例,这意味着对ComplexObject实例的多个引用。为什么在“select distinct”查询中会发生这种情况
我使用的JPA框架是hibernate,DB是HyperSQL
第一个问题与使用p6spy日志框架有关,该框架打印了一个大型DB表中的所有结果。日志记录格式导致错误的假设,即许多查询在哪里执行
在尝试微调性能时,使用本机查询似乎没有比使用JPQL查询具有更好的性能。
使用本机查询也会产生对象类型的结果,这需要后期处理。您可以使用视图对象仅接收所需的列:
StringBuilder sb = new StringBuilder();
sb.append(" SELECT new ").append(ObjectVO.class.getName()).append("(co.someInfo1, co.someInfo2, so1.someInfo )");
sb.append(" FROM ComplexObject co ");
sb.append(" JOIN co.subOject1s so1 ");
sb.append(" LEFT JOIN so1.so2 so2 ");
sb.append(" WHERE so1.id = :idSo1 AND so2 = :someThing");
Query q = em.createQuery(sb.toString());
q.setParameter("idSo1", idSo1);
q.setParameter("someThing", someThing);
List<ObjectVO> listResult = q.getResultList();
最有效的查询是类型化本机查询。如果您无法使用Hibernate或其他ORM开销,请不要使用条件或JPQL查询。@Baldurian:使用JPQL在一个事务中获取大部分数据库数据的一般概念有问题吗?在这种情况下,应该使用本机查询类型化本机查询如何比条件或JPQL查询更有效?命名查询的大多数处理都可以提前完成,并且无论是本地查询还是JPQL查询,都可以同样高效或低效,具体取决于查询本身。本机查询允许自定义,但大多数JPA提供程序都提供了一系列选项,如果您了解自己正在做什么,这些选项可以提高性能。@RannLifshitz一般来说,但是如果你不能忍受几个Hibernate愚蠢的查询,而且它们经常发生,你应该切换到本机查询。添加Hibernate标记作为第2部分中的行为是JPA提供者特有的。JPA不支持嵌套抓取,其他提供程序处理过滤掉连接多个关系可能导致的重复项。
StringBuilder sb = new StringBuilder();
sb.append(" SELECT new ").append(ObjectVO.class.getName()).append("(co.someInfo1, co.someInfo2, so1.someInfo )");
sb.append(" FROM ComplexObject co ");
sb.append(" JOIN co.subOject1s so1 ");
sb.append(" LEFT JOIN so1.so2 so2 ");
sb.append(" WHERE so1.id = :idSo1 AND so2 = :someThing");
Query q = em.createQuery(sb.toString());
q.setParameter("idSo1", idSo1);
q.setParameter("someThing", someThing);
List<ObjectVO> listResult = q.getResultList();
public class ObjectVO {
private String info1;
private Long info2;
private String info3;
public PedidoModel(String info1, Long info2, String info3){
this.info1 = info1;
this.info2 = info2;
this.info3 = info3;
}
}