我的 O/R Mapping 之旅(三)

在本部分中,才真正開始對 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();

Transaction tx = session.beginTransaction();
  

程序第一幕馬上出場。

有位叫張三的人,他買了輛車。由於是第一次買車,進入車輛管理系統後要對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);
  }
 }
}

分別設置好 AutoInfoPeople 對象屬性後,調用 Session.save() 方法保存,然後事務提交,最後關閉 Session。好了,看看數據庫吧,一切都已保存好了。

程序第二幕出場。

張三後來做生意,自己經營得很好,打算再買輛車跑運輸。對於第二次買車,車輛管理系統的 PEOPLE 表原本已經記錄了他的基本信息,遂不對 PEOPLE 表操作。只向 AUTO_INFO 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 =
    (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);
  }
 }
}

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);
  }
 }
}

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);
  }
 }
}

  

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”表的信息。“ai.OwnerNo.Id=1”就是說通過主鍵參數爲“1”的 PEOPLE 表記錄來取出相應 AUTO_INFO 表記錄。

對於一對多(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);
  }
 }
}

  

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);
  }
 }
}

  

    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://blog.csdn.net/rosen

     

(請注意!引用、轉貼本文應註明原作者:Rosen Jiang 以及出處:http://blog.csdn.net/rosen

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章