第一個 Hibernate 程式


撰寫本文的時候,Hibernate最新的版本是3.1,請連接至 Hibernate的官方網站 進行檔案的下載。

下載zip檔案並解壓縮之後,在解開的目錄下就有Hibernate3.jar,這是Hibernate 3所需要的API之封裝,可以在doc目錄中找到API說明或相關參考文件,在lib 目錄中的則是您可能會用到的相依檔案。

對於將撰寫的第一個Hibernate程式,所需要的.jar檔案除了hibernate3.jar之外,您還需要:
  • antlr-2.7.6rc1.jar
  • asm.jar
  • cglib-2.1.3.jar
  • commons-collections-2.1.1.jar
  • commons-logging-1.0.4.jar
  • dom4j-1.6.1.jar、ehcache-1.1.jar
  • jta.jar
  • log4j-1.2.11.jar

Hibernate在底層仍是使用JDBC,所以您也必須要有JDBC的驅動程式的jar檔案。

接來撰寫個專案,示範一下Hibernate的功能與使用方式,在這個示範中暫時不使用到Spring的功能,稍後會再來改寫它,以了解Spring與 Hibernate整合之後的方便性。同樣的,先設計一個User類別,這個User類別將對應至demo資料庫中的一個user表格:
  • User.java
package onlyfun.caterpillar;

public class User {
private Integer id;
private String name;
private Integer age;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
}

User類別必須有一個id屬性,用來作為物件於程式中唯一性的識別,這個id值可以由Hibernate為您產生。

在這邊使用的MySQL資料庫,表格建立時是使用以下的SQL:
CREATE TABLE user (
    id INT(11) NOT NULL auto_increment PRIMARY KEY,
    name VARCHAR(100) NOT NULL default '',
    age INT
) TYPE = InnoDB;


User類別與user表格之間要建立對映關係,實際上是靠一個映射文件來完成,映射文件可以使用XML來撰寫,通當命名為.hbm.xml,例如設計一個User.hbm.xml映射文件:
  • User.hbm.xml
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/
→ hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="onlyfun.caterpillar.User"
table="user">

<id name="id" column="id">
<generator class="native"/>
</id>

<property name="name" column="name"/>

<property name="age" column="age"/>

</class>
</hibernate-mapping>

在映射文件中,<class>標籤用來定義類別與表格的對映,"name"屬性用來設定類別名稱,"table"屬性用來設定表格名稱; <id>標籤中"name"屬性用來設定物件的唯一性識別id,通常對應至資料表中的主鍵欄位,也就是"column"屬性所設定的對應欄 位;<generator>的"class"用來設定主鍵的產生方式,設定為"native"表示依資料庫自己的主鍵生成方式來生成主鍵值, 例如我的user表格在建立時,主鍵設定為auto_increment,所以會每加入一筆資料後都自動遞增主鍵值。

接下來的<property>標籤則設定User物件的每一個屬性(由"name"屬性設定),分別對應至資料庫中user表格的哪一個欄位(由"column"屬性設定)。

接著同樣的,設計一個IUserDAO介面,讓應用程式在存取資料庫時,依賴於抽象的介面而非實際的類別實作,如下所示:
  • IUserDAO.java
package onlyfun.caterpillar;

public interface IUserDAO {
public void insert(User user);
public User find(Integer id);
}

然後由UserDAO類別來實作IUserDAO介面,這次實作時使用Hibernate的API,需要注入一個org.hibernate.SessionFactory物件:
  • UserDAO.java
package onlyfun.caterpillar;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

public class UserDAO implements IUserDAO {
private SessionFactory sessionFactory;

public UserDAO() {
}

public UserDAO(SessionFactory sessionFactory) {
this.setSessionFactory(sessionFactory);
}

public void setSessionFactory(
SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

public void insert(User user) {
// 取得Session
Session session = sessionFactory.openSession();
// 開啟交易
Transaction tx= session.beginTransaction();
// 直接儲存物件
session.save(user);
// 送出交易
tx.commit();
session.close();
}

public User find(Integer id) {
Session session = sessionFactory.openSession();

User user = (User) session.get(User.class, id);

session.close();

return user;
}
}

在Hibernate中,SessionFactory是用來管理org.hibernate.Session,Session的作用類似於JDBC中 Connection的作用,在Hibernate中每次進行資料存取之前都必須開啟Session,在進行資料變更或儲存時,則必須開啟交易,在儲存資 料的時候,您可以使用Session的save()方法直接將物件儲存,在org.hibernate.Transaction執行commit()方法 之後,Hibernate會根據映射文件,將物件中的各個屬性資料轉換並儲存至user表格中對應的欄位。

在不使用資料庫連線的時候,要記得使用close()方法關閉Session,關閉Session並不等於關閉Connection,在 Hibernate中如果您有使用連接池(Connection pool),在Session的close()方法執行完畢後,會將Connection置回連接池之中,而不是直接關閉。

而在UserDAO的find()方法實作中,您可以直接使用Session的get()方法,指定資料的id值與要封裝資料的類別型態,接著查詢回來的物件中就包括了相對應的資料,將之轉換回User型態,您就可以操作User物件上各種方法來取得資料。

在使用Hibernate時,還必須定義一個設定檔,告知資料庫名稱、使用者名稱、密碼、映射文件位置等,可以使用XML檔案來定義,檔名為hibernate.cfg.xml,如下所示:
  • hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/
→ hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
<property name="show_sql">
true
</property>

<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>

<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>

<property name="connection.url">
jdbc:mysql://localhost/demo
</property>

<property name="connection.username">
caterpillar
</property>

<property name="connection.password">
123456
</property>

<!-- 以下設置物件與資料庫表格映射文件 -->
<mapping resource="onlyfun/caterpillar/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>

在<session-factory>的設定中,"show_sql"被設定為true,表示在執行資料庫存取動作時顯示Hibernate 所生成、使用的SQL語法;Hibernate可以使用許多不同的資料庫,不同的資料庫在SQL或操作上會有所差別,可以設定"dialect"來表示將 使用哪一種資料庫適用的語句操作,由於這邊所使用的是MySQL資料庫,所以設定為 org.hibernate.dialect.MySQLDialect;接著來的"connection.driver_class"、 "connection.url"、"connection.username"、"connection.password"分別用以設定JDBC驅動 程式類別、URL、使用者名稱與密碼。

在<mapping>中的"resource"設定的是物件與資料庫表格的映射文件位置,在上面的設定為 onlyfun/caterpillar/User.hbm.xml,表示檔案在Classpath路徑下的onlyfun資料夾的 caterpillar資料夾下,通常hbm.xml建議與對應的Java類別放置在一起。

接著就是建立org.hibernate.cfg.Configuration物件來讀取設定檔,它是hibernate.cfg.xml中相關設定的具 體代表物件,Configuration物件建立之後就不會變動,如果您修改了設定檔案的內容,則必須另外再產生新的Configuration物件,新 的變更才會被再次讀取。

直接來看一個簡單的程式,了解如何使用以上設計的程式進行資料的儲存與查詢:
  • HibernateDemo.java
package onlyfun.caterpillar;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateDemo {
public static void main(String[] args) {
// Configuration 負責管理 Hibernate 配置訊息
Configuration config =
new Configuration().configure();
// 根據 config 建立 SessionFactory
// SessionFactory 將用於建立 Session
SessionFactory sessionFactory =
config.buildSessionFactory();

// 建立DAO物件
IUserDAO userDAO = new UserDAO(sessionFactory);

User user = new User();
user.setName("caterpillar");
user.setAge(new Integer(30));

userDAO.insert(user);

user = userDAO.find(new Integer(1));

System.out.println("name: " + user.getName());
}
}

在建立Configuration物件之後,就可以使用它當中所包括的資訊來建立SessionFactory物件,接著在建立UserDAO時將SessionFactory的實例指定給它,然後您就可以操作UserDAO物件來進行資料的儲存了。

有關於Hibernate更詳盡的介紹,可以參考 Hibernate