Hibernate學習筆記(二)——建立一個簡單的Hibernate專案
首先來看看Hibernate開發的一個簡單流程:
(1)準備開發環境,建立Hibernate專案。
(2)在資料庫中建立資料表。
(3)建立持久化類。
(4)設計對映檔案,使用Hibernate對映檔案將POJO物件對映到資料庫。
(5)建立Hibernate的配置檔案Hibernate.cfg.xml。
(6)編寫輔助工具類HibernateUtil類,用來實現對HIbernate的初始化並提供獲得Session的方法,此步可根據情況取捨。
(7)編寫DAO層類。
(8)編寫Service層類。
(9)編寫測試類。
下面來一步一步地做。
1.建立Eclipse專案
在Eclipse中建立一個Dynamic Web Project專案,命名為HibernateDemo。
在HibernateDemo專案名稱上右擊,在快捷選單中選擇New->Other選項,在彈出的對話方塊中找到Hibernate節點,選擇Hibernate Configuration File(cfg.xml)選項,如下圖所示:
點選Next按鈕,在彈出的對話方塊中選擇配置檔案儲存的目錄,一般預設在src目錄,同時需要輸入配置檔案的名稱,一般預設為hibernate.cfg.xml即可。繼續Next,在彈出的對話方塊中填寫資料庫方言(Database dialect)、資料庫驅動(Driver class)、資料庫URL、使用者名稱、密碼等。MySQL資料庫的配置如下:
單擊Finish,配置檔案就建立成功了,後面有需要可以繼續編輯該檔案。
2.建立資料表USER
在MySQL中建立一個名為mysqldb的資料庫,在該資料庫中建立一張名為USER的表。建立USER表的語句如下:
create table user(
user_id int(11),
name varchar(20),
password varchar(12),
type varchar(6),
primary key(user_id));
建立好的USER表在MySQL中顯示如下:
mysql> describe user; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | user_id | int(11) | NO | PRI | 0 | | | name | varchar(20) | YES | | NULL | | | password | varchar(12) | YES | | NULL | | | type | varchar(6) | YES | | NULL | | +----------+-------------+------+-----+---------+-------+
3.編寫POJO對映類User.java
package org.hibernate.entity;
public class User {
private int id;//持久化類的標識屬性,對映到資料表中的主鍵列
private String name;
private String password;
private String type;
public User() {
// TODO Auto-generated constructor stub
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
4.編寫對映檔案User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2014-12-28 22:18:36 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<!-- name 持久化類的類名,table 資料表的表名,MySQL不區分大小寫 -->
<class name="org.hibernate.entity.User" table="USER">
<!-- 將User類中的id屬性對映為資料表USER中的主鍵列user_id -->
<id name="id" type="int">
<column name="USER_ID" />
<generator class="native" />
</id>
<!-- 對映User類的name屬性 -->
<property name="name" type="java.lang.String">
<column name="NAME" length="20"/>
</property>
<!-- 對映User類的password屬性 -->
<property name="password" type="java.lang.String">
<column name="PASSWORD" length="12"/>
</property>
<!-- 對映User類的type屬性 -->
<property name="type" type="java.lang.String">
<column name="TYPE" length="6"/>
</property>
</class>
</hibernate-mapping>
5.編寫hibernate.cfg.xml配置檔案
前面我們通過Hibernate Tools的嚮導工具新建了一個hibernate.cfg.xml配置檔案,其實我們也可以直接在src目錄下新建一個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>
<!-- 資料庫的JDBC驅動 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 資料庫的URL -->
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/mysqldb</property>
<!-- 資料庫的使用者名稱和密碼 -->
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<!-- 資料庫的方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Hibernate自動根據對映檔案建立或者更新資料表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 在控制檯輸出執行時生成的SQL語句,方便除錯 -->
<property name="show_sql">true</property>
<!-- 連線池大小 -->
<property name="connection.pool_size">1</property>
<!-- 列出所有對映檔案 -->
<mapping resource="org/hibernate/entity/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
6.編寫輔助工具類HibernateUtil.java
package org.hibernate.entity;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static SessionFactory sessionFactory;
// 建立執行緒區域性變數threadLocal,用來儲存Hibernate的Session
private static final ThreadLocal<Session> threadLocal=new ThreadLocal<Session>();
// 使用靜態程式碼塊初始化Hibernate
static
{
try
{
// 讀取配置檔案
Configuration cfg=new Configuration().configure();
// 建立SessionFactory
sessionFactory=cfg.buildSessionFactory();
}catch(Throwable ex)
{
throw new ExceptionInInitializerError(ex);
}
}
// 獲得SessionFactory的例項
public static SessionFactory getsSessionFactory()
{
return sessionFactory;
}
// 獲得ThreadLocal物件管理的Session
public static Session getsSession() throws HibernateException
{
Session session=(Session) threadLocal.get();
if(session==null||!session.isOpen())
{
if(sessionFactory==null)
{
rebuildSessionFactory();
}
// 通過SessionFactory物件建立Session物件
session=(sessionFactory!=null)?sessionFactory.openSession():null;
// 將Session物件儲存到執行緒區域性變數threadLocal中
threadLocal.set(session);
}
return session;
}
// 關閉Session例項
public static void closeSession()
{
// 從執行緒區域性變數threadLocal中獲取之前存入的Session例項
Session session=(Session)threadLocal.get();
threadLocal.set(null);
if(session!=null)
{
session.close();
}
}
// 重建SessionFactory
public static void rebuildSessionFactory()
{
Configuration configuration=new Configuration();
configuration.configure("/hibernate.cfg.xml");
sessionFactory=configuration.buildSessionFactory();
}
// 關閉快取和連線池
public static void shutdown()
{
getsSessionFactory().close();
}
}
7.編寫DAO層介面UserDAO.java
package org.hibernate.dao;
import org.hibernate.entity.User;
public interface UserDAO {
void save(User user);
User findById(int id);
void delete(User user);
void update(User user);
}
8.編寫DAO層實現類UserDAOImpl.java
package org.hibernate.dao;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.entity.HibernateUtil;
import org.hibernate.entity.User;
public class UserDAOImpl implements UserDAO {
// 新增使用者
@Override
public void save(User user) {
// TODO Auto-generated method stub
// 建立Session例項
Session session = HibernateUtil.getsSession();
// 建立Transaction例項
Transaction tx = session.beginTransaction();
try {
// 使用Session的save方法將持久化物件儲存到資料庫
session.save(user);
// 提交事務
tx.commit();
} catch (Exception e) {
e.printStackTrace();
// 出現異常,回滾事務
tx.rollback();
} finally {
// 關閉Session連線
HibernateUtil.closeSession();
}
}
// 根據id查詢使用者
@Override
public User findById(int id) {
// TODO Auto-generated method stub
User user = null;
Session session = HibernateUtil.getsSession();
Transaction tx = session.beginTransaction();
try {
// 使用session的get方法獲取指定id的使用者
user = (User) session.get(User.class, id);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
HibernateUtil.closeSession();
}
return user;
}
// 刪除使用者
@Override
public void delete(User user) {
// TODO Auto-generated method stub
Session session = HibernateUtil.getsSession();
Transaction tx = session.beginTransaction();
try {
// 使用session的delete方法將持久化物件刪除
session.delete(user);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
HibernateUtil.closeSession();
}
}
// 修改使用者資訊
@Override
public void update(User user) {
// TODO Auto-generated method stub
Session session = HibernateUtil.getsSession();
Transaction tx = session.beginTransaction();
try {
// 使用session的update方法更新持久化物件
session.update(user);
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession();
}
}
}
通過以上步驟,一個Hibernate專案就完成了,下面我們來測試一下。
9.編寫測試類UserTest.java
在HibernateDemo專案名稱上右擊,選擇Properties,在彈出的視窗左側選擇Java Build Path選項,然後在右側介面中選擇Libraries標籤,點選Add Library按鈕,在彈出的視窗中選擇Junit,如下圖所示:
然後點選Next,在version一欄選擇Junit 4,然後點選Finish。這樣Junit包就引入到專案中了。
接下來在專案中新建org.hibernate.test包,在包名上右擊,依次選擇New->Junit Test Case選單,在彈出的視窗中填寫測試類的名稱和需要測試的類的名稱(這個需要填寫完整包名),如下圖所示:
點選Next按鈕,可以選擇需要測試的方法,根據需要選擇即可。
點選Finish,系統會自動生成UserTest類的框架,裡面包含了一些空方法,我們將需要測試的方法進行重寫就可以了。
這裡以save方法為例,重寫testSave方法。
package org.hibernate.test;
import org.hibernate.dao.UserDAO;
import org.hibernate.dao.UserDAOImpl;
import org.hibernate.entity.User;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
public class UserTest {
@AfterClass
public static void tearDownAfterClass() throws Exception {
}
@Before
public void setUp() throws Exception {
}
// @Test 註釋表名是一個測試方法
@Test
public void testSave() {
UserDAO userDAO=new UserDAOImpl();
try{
User u=new User();
// 設定User物件的各個屬性
u.setId(20);
u.setName("zhangsan");
u.setPassword("123456");
u.setType("admin");
// 使用UserDAOImpl的save方法將User物件存入到資料庫
userDAO.save(u);
}catch(Exception e){
e.printStackTrace();
}
}
}
接下來在UserTest.java檔名稱上右擊,依次選擇Run As ->Junit Test選單,我們可以在Eclipse的Junit View中看到測試結果,如果進度條正確,表示結果正確,如果進度條為紅色,表明有錯誤,我們可以看到有什麼錯誤。
然後我們到資料庫中看看資料有沒有正確儲存到資料庫。
mysql> select * from user;
+---------+----------+----------+-------+
| USER_ID | NAME | PASSWORD | TYPE |
+---------+----------+----------+-------+
| 1 | zhangsan | 123456 | admin |
+---------+----------+----------+-------+
這裡可能有人會感到奇怪,為什麼UserTest類中設定了id為20,結果儲存到資料庫中確是1呢?
因為我們在User.hbm.xml檔案中將id設定成了主鍵,如下所示:
<!-- 將User類中的id屬性對映為資料表USER中的主鍵列user_id -->
<id name="id" type="int">
<column name="USER_ID" />
<generator class="native" />
</id>
其中的generator元素指的是主鍵生成策略,hibernate會按照主鍵生成策略為id賦值,而不會將程式中的id值儲存到資料庫。最後結合上面的專案我們再看看Hibernate的工作原理:
(1)Hibernate初始化,建立Configuration物件。
a)從Hibernate配置檔案hibernate.properties或者hibernate.cfg.xml中讀取配置資訊,存放到Configuration物件中。
b)根據配置檔案中的mapping元素載入所有實體類對應的對映檔案到Configuration物件中。
說明:Hibernate可以採取兩種形式的配置檔案,一種是hibernate.properties檔案,另一種是hibernate.cfg.xml檔案。這兩種檔案本質上是一樣的,都可以完成對Hibernate的配置工作,在實際開發中,更多地採用XML格式的配置檔案。若兩種配置檔案同時存在且都有相同的配置資訊,則hibernate.cfg.xml中的配置會覆蓋掉hibernate.properties中的配置,這其中的原因結合程式碼來解釋。看如下程式碼:
Configuration cfg=new Configuration().configure();
這是建立Configuration例項並讀取配置檔案的程式碼。
- 當執行new Configuration()方法時,Hibernate會在classpath的根目錄下查詢hibernate.properties檔案。如果找到了該檔案,則所有的hibernate.*的屬性被裝載到Configuration物件中。
- 當呼叫configure()方法時,Hibernate會在classpath根目錄下查詢hibernate.cfg.xml。如果找不到則丟擲HibernateException。如果hibernate.cfg.xml中的某些屬性和hibernate.properties中的重複了,則會覆蓋。
(2)建立SessionFactory例項。
Configuration物件將配置資訊存入SessionFactory的屬性中,建立完SessionFactory例項,Configuration物件的使命就結束了,SessionFactory與Configuration之間的關聯也斷開了。SessionFactory充當資料來源的代理,並負責建立Session物件。
- SessionFactory例項是全域性唯一的,它對應著應用程式中的資料來源,一個數據源只需要一個SessionFactory例項,只有當應用中有多個數據源時,才為每個資料來源建立一個SessionFactory例項。
- SessionFactory的例項是重量級的,建立和銷燬都要消耗較多資源,因此只建立一次。
- 通過SessionFactory可以獲得多個Session例項。
- SessionFactory是執行緒安全的,可以被多個執行緒共享。Session不是執行緒安全的,多個併發執行緒同時操作一個Session例項時會出現問題,通常使用ThreadLocal模式管理Session。
(3)建立Session例項,建立資料庫連線。
SessionFactory可以有兩種方式建立Session。
a)openSession()方法。此方法直接建立一個新的Session例項,使用完之後需要呼叫close方法手動關閉。
b)getCurrentSession()方法。此方法建立的Session例項會繫結到當前執行緒,在事務提交(commit)或回滾(rollback)後會自動關閉。使用此方法必須在hibernate.cfg.xml配置檔案中新增如下配置:
<!-- 如果使用的是本地事務 -->
<propertyname="hibernate.current_session_context_class">thread</property>
<!-- 如果使用的是全域性事務 -->
<propertyname="hibernate.current_session_context_class">jta</property>
(4)建立Transaction例項,開始一個事務。
Hibernate的事務是對資料庫底層事務的封裝,在對Hibernate進行增、刪、改操作的時候必須先建立一個Transaction物件,一個事務就是一個原子操作。
(5)利用Session的方法進行持久化操作。將實體物件持久化到資料庫中。
(6)提交事務。
(7)關閉Session,斷開與資料庫的連線。