在 Hibernate 中直接操作 JDBC 介面

來源:互聯網
上載者:User
編輯器載入中...在 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:

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(curAmountotherAmount)
{
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 fetchObjects(ResultSet rs)
{
ArrayList ret = new ArrayList();
//example:
//while(rs.next())
//{
//Object object = new Object();
//rs.getString(1);
//rs.getString(2);
//ret.add(object);
//}
return ret;
}

public ArrayList getObjectsBySql(String pureSql)
{
Connection con = curSeesion.connection();
ps = con.prepareStatement(sqlbuf.toString());
rs = ps.executeQuery();
try
{
return this.fetchObjects(rs);

}
catch(Exception es)
{
System.out.println(es.getMessage());
return null;
}
finally
{
try
{
ps.close();
rs.close();
con.close();
}
catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}
}

使用該解決方案時,只需要將程式碼封裝解壓至項目原始碼目錄,在想要直接操作 JDBC 介面的 DAO 模組繼承 BaseHibernateDao 類,然後重寫 fetchObjects 方法填入從自身資料庫表欄位填充到領域對象的操作 , 即可輕鬆調用 getObjectsBySql 傳入原生 SQL 陳述式,返回具體的領域對象實體集合,當然使用者也可以通過 getConnection 獲得 JDBC 的 Connection 執行個體來進行自己需要的特定的 JDBC 底層操作。
仍然以上文中的 A、B、C 表為例,採用該解決方案完成 top10 取數的程式碼範例如下:

清單 7. 使用解決方案樣本

public class testDAO extends BaseHibernateDao{

private String sqlQuery = " select tab1.ID,tab1.sumCol+tab2.sumCol"+
" from(select a.ID, count(b.ID) sumCol"+
" from A a left join B b on a.ID=b.ID"+
" GROUP BY a.ID)tab1, "+
" (select a.ID,count(c.ID) sumCol"+
" from A a left join C c on a.ID=c.ID"+
" GROUP BY a.ID)tab2"+
" where tab1.ID=tab2.ID"+
" order by tab1.sumCol+tab2.sumCol desc";

@override
public ArrayList fetchObjects(ResultSet rs)
{
ArrayList ret = new ArrayList();
int count=1;
while(rs.next())
{
A a = new A();
a.setId(rs.getLong(1));
System.out.println("top"+(count++)+" amount:"+rs.getLong(2));
ret.add(object);
}
return ret;
}

}

解決方案驗證
在實際 mySql 資料庫環境中,以 A 表資料量 1000 條,B 表資料量 3W 多條,C 表資料量 2000 條情況下進行上文中提到的 top10 的操作,採用 Hibernate 的耗時和用 JDBC 介面解決方案的效率比較如下:

表 1. Hibernate 架構方式與 JDBC 介面方式效率比較 1:
Hibernate 架構方式採用 JDBC 介面解決方案
查詢耗時 1475ms 1096ms
排序耗時 1035ms 0ms
總計: 2110ms 1096ms

A 表資料量 2000 條,B 表資料量 6W,C 表資料量 4000 條情況下,採用 Hibernate 的耗時和用 JDBC 介面解決方案的效率比較:

表 2. Hibernate 架構方式與 JDBC 介面方式效率比較 2:
Hibernate 架構方式採用 JDBC 介面解決方案
查詢耗時 2836ms 1657ms
排序耗時 1568ms 0ms
總計: 4404ms 1657ms

由以上結果可以看出:在資料量遞增的情況下,採用 Hibernate 方式下效率與庫表資料呈線性增長,且排序的操作的效率也是一樣,而直接採用 JDBC 介面解決方案下效率遠遠高於 Hibernate 方式,且在資料量增長的情況下耗時的增長速度處於合理的區間內。
回頁首
總結
本文分析了 Hibernate 架構在處理複雜查詢功能上的效率問題,提出並實現了一個在 Hibernate 架構內提供直接 JDBC 操作介面的解決方案,並實際驗證了該解決方案的有效性,文中的原始碼可以直接運用於選擇 Hibenrate 架構作為資料持久層實現的 J2EE 項目,使之具備操作底層 JDBC 的功能。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.