hibernate多表查询 在 Hibernate 中直接操作 JDBC 接口

  • 格式:docx
  • 大小:44.94 KB
  • 文档页数:14

在 Hibernate 中直接操作 JDBC 接口

简介: Hibernate 在处理多表关联及分组排序等复杂数据库查询操作时,其固有的 O-R 映射机制会产生大量冗余 SQL 操作,系统性能比传统的 JDBC 低很多。本文分析了 Hibernate 产生此类问题的原因,提出了一个在 Hibernate 框架内直接操作 JDBC 的接口的解决方案,在实际项目中验证了该解决方案可以有效提高此类查询的效率。文中提供的示例代码可以直接运用于使用 Hibernate 框架的 J2EE 系统项目。

在 Hibernate 框架中提供直接操作 JDBC 接口的原因

Hibernate 框架在处理复杂查询方面的问题

Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用面向对象编程思维来操纵数据库。Hibernate 的优势在于屏蔽了数据库细节,对于新增修改删除的数据层操作,不再需要跟具体的 SQL 语句打交道,简单的对对象实例进行增删改操作即可。

但是,对于多表关联、分组统计、排序等复杂的查询功能时,由于 Hibernate 自身的 O-R 映射机制,父子表之间关联取数据会产生大量冗余的查询操作,性能低下。此类情况下,直接使用 JDBC 的 SQL 语句反而更加灵活和高效。

Hibernate 框架处理复杂查询问题实例分析

考虑如下数据库实体示例,表 A 为主表,表 B 和表 C 为子表,A 与 B、A 与 C

表均为 1 对多关系,在 B 表和 C 表中以 A_ID 外键字段关联 A 表父记录。

图 1. 数据库实体示例图

在 Hibernate 框架中,通常采用以下配置方式完成 A 表与 B,C 表父子实体之间的级联查询操作,Hibernate 实体配置 xml 如下:

清单 1. hibernate 实体配置 xml

A.hbm.xml:

lazy="false">

lazy="false">

B.hbm.xml:

C.hbm.xml

对应的 Hibernate 领域实体类代码示例如下:

清单 2. hibernate 实体类示例

A.java:

public class A implements java.io.Serializable,Comparable {

private long id;

private Set children_b = new HashSet();

private Set children_c = new HashSet();

public A(long id) {

this.id = id;

}

public long getId() {

return id;

}

public void setId(long id) {

this.id = id;

}

public Set getChildern_b() {

return children_b;

}

public void setChildren_b (Set children_b) {

this.children_b = children_b;

}

public Set getChildern_c() {

return children_c;

}

public void setChildren_c (Set children_c) {

this.children_c = children_c;

}

public int compareTo(Object other) {

A otherSubject = (A)other;

long

curAmount=this.getChildren_b().size()+this.getChildren_c().size();

long otherAmount =otherSubject.getChildren_b().size()

+ otherSubject.getChildren_c().size();

if(curAmount

{

return -1;

}

else if(curAmount>otherAmount)

{

return 1;

}

else

{

return 0;

}

}

}

B.java:

public class B implements java.io.Serializable,Comparable {

private long id;

private long a_id;

public long getId() {

return id;

}

public void setId(long id) {

this.id = id; }

public long getA_id() {

return a_id;

}

public void setA_id(long a_id) {

this.a_id = a_id;

}

public B(long id) {

this.id=id;

}

}

C.java:

public class C implements java.io.Serializable,Comparable {

private long id;

private long a_id;

public long getId() {

return id;

}

public void setId(long id) {

this.id = id;

}

public long getA_id() {

return a_id;

}

public void setA_id(long a_id) {

this.a_id = a_id;

}

public C(long id) {

this.id=id;

}

}

假设现在要统计 A 表中从属的 B 表和 C 表记录之和最高的 top10 的 A 表记录,在 Hibernate 框架下,由于取 A 表对应的数据库记录时,已关联取出了对应的 B、C 表子记录存放于 A 实体类的 children_a,children_c 的属性中,因此 top10 的功能可以通过比较每个 A 表实体类中 children_a、children_c

的 Set 的 size 大小并进行排序得到,其代码示例如下:

清单 3. 排序代码示例

private ArrayList sortAByAmount(ArrayList all)

{

for(int i=0;i

{

for(int j=0;j

{

if(all.get(j).compareTo(all.get(j+1))<=0)

{

A temp = all.get(j);

all.set(j,all.get(j+1));

all.set(j+1,temp);

}

}

}

return all;

}

表面看来很方便,但是由于 Hibernate 是面向对象的 O-R 映射机制,每一条 A

表记录的查询实际都关联有两条 B、C 表查询的 SQL 产生,我们可以看到

Hibernate 的 SQL 日志中:

清单 4. Hibernate sql 日志示例

Hibernate: select a0_.ID as ID2_ from A a0_ where a0_.ID='1'

Hibernate: select b0_.ID as ID2_,b0_.A_ID as A_ID2_ from B b0_ where

b0_.ID=?

Hibernate: select c0_.ID as ID2_,c0_.A_ID as A_ID2_ from C c0_ where

c0_.ID=?