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=?