在本部分中,才真正開始對 AUTO_INFO 和 PEOPLE 表進行操作。
要讓 Hibernate 跑起來,還要了解其中幾個關鍵對象:
net.sf.hibernate.cfg.Configuration 的實例負責管理 Hibernate 配置信息,比如數據庫連接、數據庫 dialect,還有最重要的映射文件初始化工作。
程序為了得到 Session 實例,必須先要得到它的工廠 net.sf.hibernate.SessionFactory,SessionFactory 的實例由 Configuration 構造。
net.sf.hibernate.Session 是一切數據庫操作的基礎,和 JDBC 的 Connection 意義一樣,Session 實例由 SessionFactory 獲得。
net.sf.hibernate.Transaction 的實例由 Session 獲得。Hibernate 不具備事務管理能力,Hibernate 將其委托給底層的 JDBC 或者 JTA,以實現事務管理和調度功能。在本文中使用 JDBC 事務管理。
把以上的知識串起來吧:
Configuration cfg = new Configuration().configure(); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(); Transaction tx = session.beginTransaction(); 程序第一幕馬上出場。
Configuration cfg = new Configuration().configure();
SessionFactory sessions = cfg.buildSessionFactory();
Session session = sessions.openSession();
有位叫張三的人,他買了輛車。由于是第一次買車,進入車輛管理系統后要對AUTO_INFO 和 PEOPLE 表都進行 insert 操作。
形成的一對多(one-to-many)關系保存如下:
package com.dao; import java.util.*; import net.sf.hibernate.*;import net.sf.hibernate.cfg.*; import bo.*; public class Test { List list; AutoInfo ai=new AutoInfo(); People people=new People(); public void DoTest() { try { Configuration cfg = new Configuration().configure(); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(); Transaction tx = session.beginTransaction(); people.setAddress("中國"); people.setName("張三"); people.addToAutoInfoSet(ai); ai.setLicensePlate("A00001"); ai.setOwnerNo(people); session.save(people); tx.commit(); session.close(); } catch (Exception e) { System.out.println(e); } }}
package com.dao;
import java.util.*;
import net.sf.hibernate.*;import net.sf.hibernate.cfg.*;
import bo.*;
public class Test {
List list; AutoInfo ai=new AutoInfo(); People people=new People(); public void DoTest() { try { Configuration cfg = new Configuration().configure(); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(); Transaction tx = session.beginTransaction(); people.setAddress("中國"); people.setName("張三"); people.addToAutoInfoSet(ai); ai.setLicensePlate("A00001"); ai.setOwnerNo(people); session.save(people); tx.commit(); session.close(); } catch (Exception e) { System.out.println(e); } }}
分別設置好 AutoInfo、People 對象屬性后,調用 Session.save() 方法保存,然后事務提交,最后關閉 Session。好了,看看數據庫吧,一切都已保存好了。
程序第二幕出場。
張三后來做生意,自己經營得很好,打算再買輛車跑運輸。對于第二次買車,車輛管理系統的 PEOPLE 表原本已經記錄了他的基本信息,遂不對 PEOPLE 表操作。只向 AUTO_INFO表 insert 一條車輛記錄即可。
package com.dao; import java.util.*; import net.sf.hibernate.*;import net.sf.hibernate.cfg.*; import bo.*; public class Test { List list; AutoInfo ai = new AutoInfo(); People people = new People(); public void DoTest() { try { Configuration cfg = new Configuration().configure(); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(); Transaction tx = session.beginTransaction(); people = (People) session .find( "from People where OWNER_ID=1") .get(0); ai.setLicensePlate("A00002"); ai.setOwnerNo(people); people.getAutoInfoSet().add(ai); session.save(people); tx.commit(); session.close(); } catch (Exception e) { System.out.println(e); } }}
List list; AutoInfo ai = new AutoInfo(); People people = new People(); public void DoTest() { try { Configuration cfg = new Configuration().configure(); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(); Transaction tx = session.beginTransaction(); people = (People) session .find( "from People where OWNER_ID=1") .get(0); ai.setLicensePlate("A00002"); ai.setOwnerNo(people); people.getAutoInfoSet().add(ai); session.save(people); tx.commit(); session.close(); } catch (Exception e) { System.out.println(e); } }}
session.find() 方法返回一個 List 接口的實例,里面封裝著 PO,其中的 “from People where OWNER_ID=1” 就是大名鼎鼎的 HQL(Hibernate Query Language) 了,是不是很像 SQL 呢?PEOPLE 表和 AUTO_INFO 表存在一對多關系,也就需要 People 對象來持有多個 AutoInfo 對象(以 Set 接口的實例封裝,參看People類源代碼),再通過 people.getAutoInfoSet().add(ai) 為 AUTO_INFO 表添加一條新紀錄。好了,執行完以后,再檢查數據庫吧。
這段代碼
people = (People) session.find("from People where OWNER_ID=1").get(0);可以和
people =(People) session.load(People.class,new Integer(1));互換。在本例中 List 接口實例 size() 為 1,即其中只有一個 PO;而 session.load() 是根據持久對象和主鍵來返回相應 PO,也只是單個。所以這兩種方式返回的都是相同 PO。采用哪種方式由你決定。
到這里,也許你會有這樣的想法:“應該可以直接向 AUTO_INFO 表插入記錄,不通過 People 對象中轉,像寫 SQL 一樣 Easy。” 錯了!以前直接寫 SQL 是可以辦到的,不過現在我們用的可是 Hibernate ,一切都要以對象行事,看見 ai.setOwnerNo(people) 了嗎?傳入參數是個 People 對象實例,不是簡單的字段喔。
程序第三幕出場。
呵呵,這個第三幕是最簡單的了,第一種一對多(one-to-many)的查詢:
package com.dao; import java.util.*; import net.sf.hibernate.*;import net.sf.hibernate.cfg.*; import bo.*; public class Test { List list; AutoInfo ai = new AutoInfo(); People people = new People(); public void DoTest() { try { Configuration cfg = new Configuration().configure(); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(); List list = session.find( "select ai from AutoInfo as ai where ai.OwnerNo.Id=1"); for (int i = 0; i < list.size(); i++) { ai=(AutoInfo)list.get(i); System.out.println(ai.getLicensePlate()); people=ai.getOwnerNo(); System.out.println(people.getName()); System.out.println(people.getAddress()); } session.close(); } catch (Exception e) { System.out.println(e); } }} 到了年底,查查張三一共有多少輛車。”select ai from AutoInfo as ai where ai.OwnerNo.Id=1”,這句 HQL 要找的是 AutoInfo 對象,而傳統 SQL 這么寫:“select p.name,p.address,ai.license_plate from people p,auto_info ai where p.owner_id=1”。由于 AUTO_INFO 表是“many”表,而 PEOPLE 表是“one”表,我的做法是以“many”表為基礎返回它的多個 PO,其中再持有“one”表的信息?!癮i.OwnerNo.Id=1”就是說通過主鍵參數為“1”的 PEOPLE 表記錄來取出相應 AUTO_INFO 表記錄。
List list; AutoInfo ai = new AutoInfo(); People people = new People(); public void DoTest() { try { Configuration cfg = new Configuration().configure(); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(); List list = session.find( "select ai from AutoInfo as ai where ai.OwnerNo.Id=1"); for (int i = 0; i < list.size(); i++) { ai=(AutoInfo)list.get(i); System.out.println(ai.getLicensePlate()); people=ai.getOwnerNo(); System.out.println(people.getName()); System.out.println(people.getAddress()); } session.close(); } catch (Exception e) { System.out.println(e); } }}
對于一對多(one-to-many)關系,還有第二種查詢方式:
package com.dao; import java.util.*; import net.sf.hibernate.*;import net.sf.hibernate.cfg.*; import bo.*; public class Test { AutoInfo ai = new AutoInfo(); People people = new People(); public void DoTest() { try { Configuration cfg = new Configuration().configure(); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(); people = (People) session.load(People.class, new Integer(1)); Iterator iterator = people.getAutoInfoSet().iterator(); System.out.println(people.getName()); System.out.println(people.getAddress()); while (iterator.hasNext()) { ai = (AutoInfo) iterator.next(); System.out.println(ai.getLicensePlate()); } session.close(); } catch (Exception e) { System.out.println(e); } }}
AutoInfo ai = new AutoInfo(); People people = new People(); public void DoTest() { try { Configuration cfg = new Configuration().configure(); SessionFactory sessions = cfg.buildSessionFactory(); Session session = sessions.openSession(); people = (People) session.load(People.class, new Integer(1)); Iterator iterator = people.getAutoInfoSet().iterator(); System.out.println(people.getName()); System.out.println(people.getAddress()); while (iterator.hasNext()) { ai = (AutoInfo) iterator.next(); System.out.println(ai.getLicensePlate()); } session.close(); } catch (Exception e) { System.out.println(e); } }}
people = (People) session.load(People.class, new Integer(1)) 取出單個 People 對象,其中持有以 Set 封裝的若干 AutoInfo 對象實例,Iterator iterator = people.getAutoInfoSet().iterator() 把 Set 立即轉化為 Iterator ,最后用 while (iterator.hasNext()) 循環取出其中的車牌號碼。
第一種一對多(one-to-many)的查詢實際上我把它轉換成了多對一(many -to- one)的查詢。這種轉換后有兩個缺點:一、由 HQL 轉為 SQL 輸出時,打印的 SQL 條數多于直接一對多(one-to-many)關系查詢;二、其中的 People 對象存在著大量冗余(只需要一個實例,結果取出了 List.size() 個相同的實例)。我們知道,數據庫的性能是有限的,構造對象的代價是高昂的,所以應盡量減少不必要的性能開銷。
雖然我個人不建議把一對多(one-to-many)查詢轉換成多對一(many -to- one)查詢,但事實上有些開發團隊卻樂意采用,即使他們知道性能有略微的降低。在還沒有更深入研究之前,各位看官有何看法呢?請注意!引用、轉貼本文應注明原作者:Rosen Jiang 以及出處:http://www.tkk7.com/rosen
Powered by: BlogJava Copyright © Rosen