本書使用SQL Server 2005數據庫。在XSCJ數據庫中創建KCB表。java
表名:KCB算法
項目名sql |
列名數據庫 |
數據類型數組 |
是否可空瀏覽器 |
默認值緩存 |
說明安全 |
課程號session |
KCH數據結構 |
char(3) |
主鍵 |
||
課程名 |
KCM |
char(20) |
是 |
||
開學學期 |
KXXQ |
smallint |
是 |
只能爲1-8 |
|
學時 |
XS |
int |
是 |
0 |
|
學分 |
XF |
int |
是 |
0 |
啓動MyEclipse,選擇【Window】→【Open Perspective】→【MyEclipse Database Explorer】菜單項,打開MyEclipse Database瀏覽器,右擊菜單,如圖4.2所示,選擇【New…】菜單項,出現如圖4.3所示的對話框,編輯數據庫鏈接驅動。
填寫要創建的鏈接的名稱「MyConn」(自定義),鏈接數據庫的URL「jdbc:sqlserver://localhost:1433;databaseName=XSCJ」,填寫數據庫的用戶名和密碼。添加數據庫驅動。
圖4.2 MyEclipse Database瀏覽器,建立一個新的鏈接
圖4.3 編輯數據庫鏈接驅動
編輯完成之後,在MyEclipse Database瀏覽器中,右擊剛纔建立的MyConn數據庫鏈接,選擇「Open connection…」菜單項,打開名爲「MyConn」的數據鏈接,如圖4.4所示。
圖4.4 打開數據庫鏈接
右擊項目名HibernateTest,選擇【MyEclipse】→【Add Hibernate Capabilites】菜單項,出現如圖4.5所示的對話框,選擇Hibernate框架應用版本及所須要的類庫。
圖4.5 選擇Hibernate版本及所需Jar包
單擊【Next】按鈕,進入如圖4.6所示界面。建立Hibernate配置文件hibernate.cfg.xml,將該文件放在src文件夾下,後面會詳細介紹該文件內容。這裏先說明添加Hibernate開發功能的步驟。
圖4.6 建立配置文件hibernate.cfg.xml
單擊【Next】按鈕,進入如圖4.7所示界面,指定Hibernate數據庫鏈接細節。因爲在前面已經配置一個名爲MyConn的數據庫鏈接,因此這裏只須要選擇DB Driver爲「MyConn」便可。
圖4.7 指定hibernate數據庫鏈接
單擊【Next】按鈕,出現如圖4.8所示界面。Hibernate中有一個與數據庫打交道重要的類Session。而這個類是由工廠SessionFactory建立的。這個界面詢問是否須要建立SessionFactory類。若是須要建立,還須要指定建立的位置和類名。這些接口都會在後面詳細介紹。單擊【Finish】按鈕,完成Hibernate的配置。
圖4.8 建立SessionFactory類來簡化Hibernate會話處理
首先在MyEclispse下建立一個名爲「org.model」的包,這個包將用來存放與數據庫表對應的Java類POJO。
打開MyEclipse Database Explorer視圖。打開前面建立的MyConn數據鏈接,選擇【XSCJ】→【dbo】→【TABLE】菜單項,右擊KCB表,選擇【Hibernate Reverse Engineering…】菜單項,如圖4.9所示,將啓動Hibernate Reverse Engineering嚮導,該向導用於完成從已有的數據庫表生成對應的Java類和相關映像文件的配置工做。
圖4.9 Hibernate反向工程菜單
首先,選擇生成的Java類和映像文件所在的位置,如圖4.10所示。POJO(Plain Old Java Object,簡單的Java對象),一般也稱爲VO(Value Object,值對象)。 使用POJO名稱是爲了避免和EJB混淆起來,其中有一些屬性及getter、setter方法。固然,若是有一個簡單的運算屬性也是能夠的,但不容許有業務方法。
圖4.10 生成Hibernate映射文件和Java類
單擊【Next】按鈕,進入如圖4.11所示的界面,選擇主鍵生成策略。
圖4.11 配置反向工程細節
點擊【Finish】,org.model包中會出現Kcb.java類和Kcb.hbm.xml。而後在hibernate.cfg.xml文件中配置映射文件<mapping resource="org/model/Kcb.hbm.xml"/>,該語句放在<session-factory>和</session-factory>之間。
在src文件夾下建立包test,在該包下創建測試類,命名爲Test.java,其代碼。
package test; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction; import org.model.Kcb; import org.util.HibernateSessionFactory; public class Test { public static void main(String[] args) { // 調用HibernateSessionFactory的getSession方法建立Session對象 Session session = HibernateSessionFactory.getSession(); // 建立事務對象 Transaction ts = session.beginTransaction(); Kcb kc = new Kcb(); // 建立POJO類對象 kc.setKch("198"); // 設置課程號 kc.setKcm("機電"); // 設置課程名 kc.setKxxq(new Short((short) 5)); // 設置開學學期 kc.setXf(new Integer(5)); // 設置學分 kc.setXs(new Integer(59)); // 設置學時 // 保存對象 session.save(kc); ts.commit(); // 提交事務 Query query = session.createQuery("from Kcb where kch=198"); List list = query.list(); Kcb kc1 = (Kcb) list.get(0); System.out.println(kc1.getKcm()); HibernateSessionFactory.closeSession(); // 關閉Session } }
由於該程序爲Java Application,因此能夠直接運行。運行程序,控制檯就會打印出「機電」。在徹底沒有操做數據庫的狀況下,就完成了對數據的插入。下面將詳細講解各文件的做用。
POJO類以下:
package org.model; public class Kcb implements java.io.Serializable { private String kch; // 對應表中KCH字段 private String kcm; // 對應表中KCM字段 private Short kxxq; // 對應表中KXXQ字段 private Integer xs; // 對應表中XS字段 private Integer xf; // 對應表中XF字段 public Kcb() { } // 上述屬性的getter和setter方法 }
能夠發現,該類中的屬性和表中的字段是一一對應的。那麼經過什麼方法把它們一一映射起來呢?就是前面提到的*.hbm.xml映射文件。這裏固然就是Kcb.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> <!-- name指定POJO類,table指定對應數據庫的表 --> <class name="org.model.Kcb" table="KCB"> <!-- name指定主鍵,type主鍵類型 --> <id name="kch" type="java.lang.String"> <column length="3" name="KCH"/> <!-- 主鍵生成策略 --> <generator class="assigned"/> </id> <!-- POJO屬性及表中字段的對應 --> <property name="kcm" type="java.lang.String"> <column length="12" name="KCM"/> </property> <property name="kxxq" type="java.lang.Short"> <column name="KXXQ"/> </property> <property name="xs" type="java.lang.Integer"> <column name="XS"/> </property> <property name="xf" type="java.lang.Integer"> <column name="XF"/> </property> </class> </hibernate-mapping>
該配置文件大體分爲3個部分:
(1)類、表映射配置
<class name="org.model.Kcb" table="KCB">
name屬性指定POJO類爲org.model.Kcb,table屬性指定當前類對應數據庫表KCB。
(2)id映射配置
<id name="kch" type="java.lang.String"> <column name="KCH" length="3" /> <generator class="assigned" /> </id>
id節點定義實體類的標誌(assigned),在這裏也就是對應數據庫表主鍵的類屬性。<generator class="assigned" />指定主鍵的生成方式。
Hibernate的主鍵生成策略分爲三大類:Hibernate對主鍵id賦值、應用程序自身對id賦值、由數據庫對id賦值。
assigned:應用程序自身對id賦值。當設置<generator class="assigned"/>時,應用程序自身須要負責主鍵id的賦值。例以下述代碼:
Kcb kc=new Kcb(); // 建立POJO類對象 kc.setKch("198"); // 設置課程號 kc.setKcm("機電"); // 設置課程名 kc.setKxxq(new Integer(5).shortValue()); // 設置開學學期 kc.setXf(new Integer(4).shortValue()); // 設置學分 kc.setXs(new Integer(59).shortValue()); // 設置學時
native:由數據庫對id賦值。當設置<generator class="native"/>時,數據庫負責主鍵id的賦值,最多見的是int型的自增型主鍵。
hilo:經過hi/lo算法實現的主鍵生成機制,須要額外的數據庫表保存主鍵生成歷史狀態。
seqhilo:與hi/lo相似,經過hi/lo算法實現的主鍵生成機制,只是主鍵歷史狀態保存在sequence中,適用於支持sequence的數據庫,如Oracle。
increment:主鍵按數值順序遞增。此方式的實現機制爲在當前應用實例中維持一個變量,以保存當前的最大值,以後每次須要生成主鍵的時候將此值加1做爲主鍵。當有多個實例訪問同一數據庫時,可能形成主鍵重複異常。
identity:採用數據庫提供的主鍵生成機制,如SQL Server、MySQL中的自增主鍵生成機制。
sequence:採用數據庫提供的sequence機制生成主鍵,如Oracle sequence。
uuid.hex:由Hibernate基於128位惟一值產生算法,根據當前設備IP、時間、JVM啓動時間、內部自增量等4個參數生成十六進制數值(編碼後長度爲32位的字符串表示)做爲主鍵。即便是在多實例併發運行的狀況下,這種算法在最大程度上保證了產生id的惟一性。固然,重複的機率在理論上依然存在,只是機率比較小。
uuid.string:與uuid.hex相似,只是對生成的主鍵進行編碼(長度16位)。
foreign:使用外部表的字段做爲主鍵。
select:Hibernate 3新引入的主鍵生成機制,主要針對遺留系統的改造工程。
(3)屬性、字段映射配置
屬性、字段映射將映射類屬性與庫表字段相關聯。
<property name="kcm" type="java.lang.String"> <column name="KCM" length="12" /> </property>
name="kcm" 指定映像類中的屬性名爲「kcm」,此屬性將被映像到指定的庫表字段KCM。type="java.lang.String"指定映像字段的數據類型。column name="KCM"指定類的kcm屬性映射KCB表中的KCM字段。
該文件是Hibernate重要的配置文件,配置該文件主要是配置SessionFractory類。
<?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> <!-- 數據庫鏈接的URL --> <property name="connection.url">jdbc:sqlserver://localhost:1433;databaseName=XSCJ</property> <!-- 數據庫鏈接的用戶名,此處爲本身數據庫的用戶名和密碼 --> <property name="connection.username">liuyanbo</property> <!-- 數據庫鏈接的密碼 --> <property name="connection.password">123456</property> <!-- SQL方言,這裏使用的是SQL Server --> <property name="dialect">org.hibernate.dialect.SQLServerDialect</property> <!-- 使用的數據庫的鏈接,咱們建立的MyConn --> <property name="myeclipse.connection.profile">MyConn</property> <!-- 數據庫JDBC驅動程序 --> <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property> <!-- 表和類對應的映射文件,若是多個,都要在這裏註冊 --> <mapping resource="org/model/Kcb.hbm.xml"/> </session-factory> </hibernate-configuration>
Hibernate配置文件主要用於配置數據庫鏈接和Hibernate運行時所須要的各類屬性。Hibernate初始化期間會自動在CLASSPATH中尋找這個文件,並讀取其中的配置信息,爲後期數據庫操做作好準備。
HibernateSessionFactory類是自定義的SessionFactory,名字能夠自定義。這裏用的HibernateSessionFactory。
package org.util; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.cfg.Configuration; public class HibernateSessionFactory { // 定義一個靜態字符串變量存放Hibernate的配置文件名 private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml"; // 建立一個線程局部變量對象 private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); // 建立一個靜態的Configuration對象 private static Configuration configuration = new Configuration(); // 定義一個靜態的SessionFactory對象 private static org.hibernate.SessionFactory sessionFactory; private static String configFile = CONFIG_FILE_LOCATION; // 根據配置文件獲得SessionFactory對象 static { try { // 獲得configuration對象 // 該句和上面建立的靜態對象合起來就爲 // configuration=new Configuration().configure(configFile); configuration.configure(configFile); sessionFactory = configuration.buildSessionFactory(); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } private HibernateSessionFactory() { } // 取得Session對象 public static Session getSession() throws HibernateException { Session session = (Session) threadLocal.get(); if (session == null || !session.isOpen()) { if (sessionFactory == null) { rebuildSessionFactory(); } session = (sessionFactory != null) ? sessionFactory.openSession() : null; threadLocal.set(session); } return session; } // 能夠調用該方法從新建立SessionFactory對象 public static void rebuildSessionFactory() { try { configuration.configure(configFile); sessionFactory = configuration.buildSessionFactory(); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } // 關閉Session public static void closeSession() throws HibernateException { Session session = (Session) threadLocal.get(); threadLocal.set(null); if (session != null) { session.close(); } } public static org.hibernate.SessionFactory getSessionFactory() { return sessionFactory; } public static void setConfigFile(String configFile) { HibernateSessionFactory.configFile = configFile; sessionFactory = null; } public static Configuration getConfiguration() { return configuration; } }
在Hibernate中,Session負責完成對象持久化操做。該文件負責建立Session對象,以及關閉Session對象。從該文件能夠看出,Session對象的建立大體須要如下3個步驟:
① 初始化Hibernate配置管理類Configuration。
② 經過Configuration類實例建立Session的工廠類SessionFactory。
③ 經過SessionFactory獲得Session實例。
Configuration負責管理Hibernate的配置信息。Hibernate運行時須要一些底層實現的基本信息。這些信息包括:數據庫URL、數據庫用戶名、數據庫用戶密碼、數據庫JDBC驅動類、數據庫dialect。用於對特定數據庫提供支持,其中包含了針對特定數據庫特性的實現,如Hibernate數據庫類型到特定數據庫數據類型的映射等。
使用Hibernate必須首先提供這些基礎信息以完成初始化工做,爲後續操做作好準備。這些屬性在Hibernate配置文件hibernate.cfg.xml中加以設定,當調用:
Configuration config=new Configuration().configure();
時,Hibernate會自動在目錄下搜索hibernate.cfg.xml文件,並將其讀取到內存中做爲後續操做的基礎配置。
SessionFactory負責建立Session實例,能夠經過Configuration實例構建SessionFactory。
Configuration config=new Configuration().configure(); SessionFactory sessionFactory=config.buildSessionFactory();
Configuration實例config會根據當前的數據庫配置信息,構造SessionFacory實例並返回。SessionFactory一旦構造完畢,即被賦予特定的配置信息。就是說,以後config的任何變動將不會影響到已經建立的SessionFactory實例sessionFactory。若是須要使用基於變動後的config實例的SessionFactory,須要從config從新構建一個SessionFactory實例。若是須要訪問多個數據庫,針對每一個數據庫,應分別建立其對應的SessionFactory實例。
SessionFactory保存了對應當前數據庫配置的全部映射關係,同時也負責維護當前的二級數據緩存和Statement Pool。因而可知,SessionFactory的建立過程很是複雜、代價高昂。這也意味着,在系統設計中充分考慮到SessionFactory的重用策略。因爲SessionFactory採用了線程安全的設計,可由多個線程併發調用。大多數狀況下,針對一個數據庫共享一個SessionFactory實例便可。
Session是Hibernate持久化操做的基礎,提供了衆多持久化方法,如save、update、delete等。經過這些方法,透明地完成對象的增長、刪除、修改、查找等操做。
同時,值得注意的是,Hibernate Session的設計是非線程安全的,即一個Session實例同時只可由一個線程使用。同一個Session實例的多線程併發調用將致使難以預知的錯誤。
Session實例由SessionFactory構建:
Configuration config=new Configuration().configure(); SessionFactory sessionFactory=config.buldSessionFactory(); Session session=sessionFactory.openSession();
Transaction是Hibernate中進行事務操做的接口,Transaction 接口是對實際事務實現的一個抽象,這些實現包括JDBC的事務、JTA 中的UserTransaction,甚至能夠是CORBA 事務。之因此這樣設計是可讓開發者可以使用一個統一的操做界面,使得本身的項目能夠在不一樣的環境和容器之間方便地移值。事務對象經過Session建立。例如如下語句:
Transaction ts=session.beginTransaction();
在Hibernate 2.x中,find()方法用於執行HQL語句。Hibernate 3.x廢除了find()方法,取而代之的是Query接口,它們都用於執行HQL語句。Query和HQL是分不開的。
Query query=session.createQuery(「from Kcb where kch=198」);
上面是直接給出查詢條件的值,也能夠是設參數,例如如下語句:
Query query=session.createQuery("from Kcb where kch=?");
就要在後面設置其值:
Query.setString(0, "要設置的值");
上面的方法是經過「?」來設置參數,還能夠用「:」後跟變量的方法來設置參數,如上例能夠改成:
Query query=session.createQuery("from Kcb where kch=:kchValue"); Query.setString("kchValue","要設置的課程號值");
因爲上例中kch爲String類型,因此要用setString(),若是是int型,就要用setInt()。通用的方法是setParameter()方法,不論是什麼類型的參數均可以。其使用方法是相同的,例如:
Query.setParameter(0, "要設置的值");
Query還有一個list()方法,用於取得一個List集合的示例,此示例中包括多是一個Object集合,也多是Object數組集合。例如:
Query query=session.createQuery("from Kcb where kch=198"); List list=query.list();
Hibernate Query Language。語法與SQL很像,但HQL是一種面向對象的查詢語言。SQL的操做對象是數據表和列等數據對象,而HQL的操做對象是類、實例、屬性等。HQL的查詢依賴於Query類,每一個Query實例對應一個查詢對象。
Query query=session.createQuery(「from Kcb where kch=198」);
HQL經常使用的幾種查詢方式:
基本查詢是HQL中最簡單的一種查詢方式。下面以課程信息爲例說明其幾種查詢狀況。
(1)查詢全部課程信息
Session session=HibernateSessionFactory.getSession(); Transaction ts=session.beginTransaction(); Query query=session.createQuery("from Kcb"); List list=query.list(); ts.commit(); HibernateSessionFactory.closeSession();
(2)查詢某門課程信息
Session session=HibernateSessionFactory.getSession(); Transaction ts=session.beginTransaction(); // 查詢一門學時最長的課程 Query query=session.createQuery("from Kcb order by xs desc"); query.setMaxResults(1); // 設置最大檢索數目爲1 // 裝載單個對象 Kcb kc=(Kcb)query.uniqueResult(); ts.commit(); HibernateSessionFactory.closeSession();
(3)查詢知足條件的課程信息
Session session=HibernateSessionFactory.getSession(); Transaction ts=session.beginTransaction(); // 查詢課程號爲001的課程信息 Query query=session.createQuery("from Kcb where kch=001"); List list=query.list(); ts.commit(); HibernateSessionFactory.closeSession();
查詢的條件有幾種狀況,下面舉例說明。
(1)按指定參數查詢
Session session=HibernateSessionFactory.getSession(); Transaction ts=session.beginTransaction(); // 查詢課程名爲計算機基礎的課程信息 Query query=session.createQuery("from Kcb where kcm=?"); query.setParameter(0, "計算機基礎"); List list=query.list(); ts.commit(); HibernateSessionFactory.closeSession();
(2)使用範圍運算查詢
Session session=HibernateSessionFactory.getSession(); Transaction ts=session.beginTransaction(); // 查詢這樣的課程信息,課程名爲計算機基礎或數據結構,且學時在40~60之間 Query query=session.createQuery("from Kcb where (xs between 40 and 60) and kcm in('計算機基礎','數據結構')"); List list=query.list(); ts.commit(); HibernateSessionFactory.closeSession();
(3)使用比較運算符查詢
Session session=HibernateSessionFactory.getSession(); Transaction ts=session.beginTransaction(); // 查詢學時大於51且課程名不爲空的課程信息 Query query=session.createQuery("from Kcb where xs>51 and kcm is not null"); List list=query.list(); ts.commit(); HibernateSessionFactory.closeSession();
(4)使用字符串匹配運算查詢
Session session=HibernateSessionFactory.getSession(); Transaction ts=session.beginTransaction(); // 查詢課程號中包含「001」字符串且課程名前面三個字爲計算機的全部課程信息 Query query=session.createQuery("from Kcb where kch like '%001%' and kcm like '計算機%'"); List list=query.list(); ts.commit(); HibernateSessionFactory.closeSession();
爲了知足分頁查詢的須要,Hibernate的Query實例提供了兩個有用的方法:setFirstResult(int firstResult)和setMaxResults(int maxResult)。其中setFirstResult(int firstResult)方法用於指定從哪個對象開始查詢(序號從0開始),默認爲第1個對象,也就是序號0。SetMaxResults(int maxResult)方法用於指定一次最多查詢出的對象的數目,默認爲全部對象。以下面的代碼片斷:
Session session=HibernateSessionFactory.getSession(); Transaction ts=session.beginTransaction(); Query query=session.createQuery("from Kcb"); int pageNow=1; // 想要顯示第幾頁 int pageSize=5; // 每頁顯示的條數 query.setFirstResult((pageNow-1)*pageSize); // 指定從哪個對象開始查詢 query.setMaxResults(pageSize); // 指定最大的對象數目 List list=query.list(); ts.commit(); HibernateSessionFactory.closeSession();