2015-10-23 85 views
1

我正在寻找优化休眠select查询的最佳方式。休眠选择查询优化

这里是一个基本的例子:

BDD模型 1个客户端 - >ñ合同 - > N个选项

到请求客户机 “XXXX” 的所有数据的最简单的方式是这样的:

final Query hqlQuery = jdbcTemplate.createHQLQuery("from Client cli left join fetch cli.contracts con left join fetch con.options where cli.id=:idClient"); 
hqlQuery .setString("idClient", "xxxx"); 

Client client = (Client) hqlQuery.uniqueResult(); 

有时这是不可能的,因为有两个数据要返回。

所以,我分裂的要求,somethink像:

// Query 1 
final Query hqlQueryClient = jdbcTemplate.createHQLQuery("from Client cli left join fetch cli.contracts where cli.id=:clientId"); 
hqlQueryClient.setString("clientId", "xxxx"); 

Client client = (Client) hqlQueryClient.uniqueResult(); 

List<String> listContractIds = new ArrayList<String>(); 

for (Contract contract : client.getContracts()) { 
    listContractIds.add(contract.getId()); 
} 

// Query 2 
final Query hqlQueryOptions = jdbcTemplate.createHQLQuery("from Option opt where opt.contract.id in(:contractIds)"); 
hqlQueryOptions.setParameterList("contractIds", listContractIds); 

List<Option> options = hqlQueryClient.list(); 

但是,与第二种方式,我不能在client对象“注入” options,所以我必须处理clientoptions对象在我的代码中,并在options列表中查找与我正在使用的合同对应的那些列表。

有没有办法用第二次请求的值来完成Hibernate对象(在我的例子中是客户端)?

感谢您的帮助。

PS:请问如果现在还不清楚,我是法国人:)

回答

0

<rant> 我一般恨冬眠,因为它是这样一个浪费时间,也似乎运行数百个查询时,你只运行如果少数写SQL手动 <\rant>

如果强行使用Hibernate,我可能会使用类似3个查询

  • from Options as o join fetch o.contract as co join fetch co.client as cl where cl = :client
  • from Contracts as co join fetch co.client as cl where cl = :client
  • from Client where clientId = :clientId

然后,我把他们都到适当Map<Long, List>地图,做Java中的连接。

+0

没有办法直接在主对象中注入3个查询的结果(而不是处理Map)? – pierrefevrier

+0

如果您只从选项 - >合同 - >客户端导航,则您可能对第一个查询正常。如果按照其他方式(客户端 - >合同 - >选项),您将按[n + 1选择](http://stackoverflow.com/questions/97197/what-is-the-n1-selects-issue)问题 –

+0

你说得对,但我无法从我的代码中的Option - > Contract - > Client中导航,我正在以另一种方式(客户端 - >合同 - >选项)进行导航。为了避免n + 1选择问题,我从来不会调用'contrat.getOptions()'。相反,我过滤结果的选项查询以编程方式(通过contrat id),但它不像只调用'contrat.getOptions()',这是这篇文章的主题:我怎么能做得更好:) – pierrefevrier

-2

使用Hibernate的好处是ORM。您可以将您的课程设置为实体。所以你不必担心简单的查询了。只需使用JPA即可完成该任务。该实体可以看起来像:

@Entity 
public class Client implements Serializable { 
    private Long id; 
    private ArrayList<Contract> contracts; 
    // more attributes here 
    @Id @GeneratedValue(strategy = GenerationType.AUTO) 
    public Long getId() { 
     return id; 
    } 

    @OneToMany 
    public ArrayList<Contract> getContracts() { 
     return contracts; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public void setContracts(ArrayList<Contract> contracts) { 
     this.contracts = contracts; 
    } 
} 

@Entity 
public class Contract implements Serializable { 
    private Long id; 
    private List<Option> options; 
    // more attributes here 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    public Long getId() { 
     return id; 
    } 

    @OneToMany 
    public List<Option> getOptions() { 
     return options; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public void setOptions(List<Option> options) { 
     this.options = options; 
    } 
} 

等等...

+1

嗨,你的回应没有上下文,我的问题不是关于映射,而是如何有效地查询 – pierrefevrier

+0

从你想强制使用Hibernate编写SQLQ的POV。由于你甚至不理解Hibernate是为什么而创建的,因此完全脱离了上下文。因此,玩得开心 – BuckRogers

0

第一:有多少数据你是否有结果的第一个查询不起作用? 如果你的结果有很多行,而你想优化这个查询,请检查你从db获得的所有数据是否真的需要。也许你应该对更扁平的其他物体进行投影。

如果您不用Java处理数据,只将它传递给前端考虑分页结果。

+0

潜在1客户 - > 50合同 - > 50选项 假设每个客户,每个合同和每个选项都有20列,这意味着Hibernate必须处理50 * 20 * 50 * 20 = 1 000 000列。 – pierrefevrier

+0

你真的需要所有这些列吗? –

+0

并非所有,但至少50%。 – pierrefevrier