1 Hibernate核心技術
1.1 理論基礎
操作數據庫的3個階段
1、 操作JDBC階段
2、 封裝JDBC
3、 ORM階段
ORM對象關係映射
持久層概念
1.2 Hibernate開發流程
步驟
1、 創建Hibernate的配置文件:該文件負責初始化Hibernate配置,包括數據庫配置和映射文件配置
2、 創建Hibernate映射文件:每一個數據表對應一個映射文件,該文件描述了數據庫中表的信息,也描述了對應的持久化類的信息
3、 創建持久化類
以上三步是開發Hibernate要實現的關鍵內容,接下來就要面向Web應用層進行編碼
1、 編寫DAO層:通過HibernateAPI編寫訪問數據庫的代碼
2、 編寫Service層:編寫業務層實現,調用DAO層類代碼
下載並安裝Hibernate
必需的包:
Hibernate3.jar
cglib-2.1.jar、asm-attrs.jar、asm.jar:CGLIB庫,用來實現PO字節碼的動態生成
dom4j-1.5.2.jar:java的XMLAPI,類似於jdom,用來讀寫XML文件的
commons-collections-2.1.1.jar
commons-logging-1.0.4.jar、log4j-1.2.9.jar:包含了日誌功能
將以上文件複製到lib目錄下
1.3 Hibernate配置文件詳解
有兩種形式:一種是XML(hibernate.cfg.xml),一種是properties屬性文件(hibernate.properties),一般使用XML
Etc子目錄下提供了默認的Hibernate配置文件hibernate.cfg.xml,複製到src目錄下,修改後如下
<hibernate-configuration> <session-factory name="foo"> <property name="myeclipse.connection.profile">JDBC for MySQL</property> <!-- 顯示執行的SQL語句 --> <property name="show_sql">true</property> <property name="connection.url">jdbc:mysql://localhost:3306/demo</property> <property name="connection.username">root</property> <property name="connection.password"></property> <property name="connection.drive_class">org.gjt.mm.mysql.Driver</property> <!-- 選擇使用的方言 --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 映射文件 --> <mapping resource="com/demo/hibernate/beans/User.hbm.xml"/> </session-factory> </hibernate-configuration>
1.4 編寫映射文件User.hbm.xml
Hibernate映射文件包含了對象/關係映射(O/R Mapping)所需的元數據。建立一個映射文件User.hbm.xml來映射到數據庫表User,映射的類名爲User,所在的包爲com.demo.hibernate.beans。如下
<?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 package="com.demo.hibernate.beans"> <class name="User" table="user"> <id name="id" column="ID" type="integer"> <generator class="native"/> //設置主鍵生成方式 </id> <property name="username" column="username" type="string"/> <property name="password" column="password" type="string"/> <property name="email" column="email" type="string"/> </class> </hibernate-mapping>
1.4.1 根元素<hibernate-mapping>
每一個hbm.xml文件都有唯一的一個根元素。Package屬性指定一個包前綴。<hibernate-mapping>元素允許嵌套多個<class>映射。但是最好的做法是一個持久化類對應一個映射文件,並以持久化的超類名稱命名
1.4.2 使用<class>定義類
<class name="User" table="user">
Class也可以是一個接口,之後可以用<subclass>來指定該接口的實際實現類。
1.4.3 使用<id>定義主鍵
如果表使用聯合主鍵,你可以映射多個屬性爲標識符屬性。下面定義了兩個字段作爲聯合主鍵。此時持久化類必須重載equals()和hashCode()方法,來實現組合標識符的相等判斷。
<composite-id>
<key-property name="username"/>
<key-property name="password"/>
</composite-id>
1.4.4 <generator>設置主鍵生成方式
<generator class="native"/>
1.4.5 Hibernate映射類型
1.4.6 使用<property>定義屬性
<property name="username" column="username" type="string"/>
1.4.7 <many-to-one>配置多對一映射
1.4.8 <one-to-one>配置一對一映射
1.4.9 Hibernate映射文件自動生成工具
1.5 編寫持久化類User.java
持久化類是指其實例需要被Hibernate持久化到數據庫中的類。Hibernate使用簡單的Java對象(Plain Old Java Objects,就是POJOs,有時也稱作Plain Ordinary Java Objects)這種編程模型來進行持久化
package com.demo.hibernate.beans; public class User { private java.lang.Integer id; private String username; private String password; private String email; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } …… }
getXXX()和setXXX()方法必須符合特定的命名規則,“get”和“set”後面緊跟屬性的名字,並且屬性名的首字母爲大寫。
如果持久化類的屬性爲boolean類型,那麼它的get方法即可以用get爲前綴,也可以用“is”爲前綴。
1.6 編寫輔助類HibernateSessionFactory.java
Session是一個持久化管理器,我們通過它來從數據加中存取User。首先,我們要從SessionFactory中獲取一個Session。通過對configure()調用來裝載hibernate.cfg.xml配置文件,並初始化成一個Configuration實例。
通常SessionFactory只是被初始化一次,例如通過一個load-on-startup servlet來初始化。這意味着你不應該在servlet中把它作爲一個實例變量來持有,而應該放在其他地方。進一步說,我們需要使用單例(Singleton)模式,才能更容易地在程序中訪問SessionFactory。下面的方法就同時解決了這兩個問題
package com.demo.hibernate.util; import org.hibernate.cfg.Configuration; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; public class HibernateSessionFactory { private static String CONFIG_FILE_LOCATION="/hibernate.cfg.xml"; private static final ThreadLocal threadLocal=new ThreadLocal(); private static final Configuration cfg=new Configuration(); private static SessionFactory sessionFactory; //取得session public static Session currentSession() throws HibernateException{ Session session=(Session)threadLocal.get(); if(session==null){ if(sessionFactory==null){ try{ cfg.configure(CONFIG_FILE_LOCATION); sessionFactory=cfg.buildSessionFactory(); }catch(Exception e){ System.err.println("%%%%Error Creating SessionFactory%%%%"); e.printStackTrace(); } } session=sessionFactory.openSession(); threadLocal.set(session); } return session; } //關閉Session對象 public static void closeSession() throws HibernateException{ Session session=(Session)threadLocal.get(); threadLocal.set(null); if(session==null){ session.close(); } } }
這個類不但在它的靜態初始器中使用了SessionFactory,還使用了一個ThreadLocal變量來保存Session作爲當前工作線程。
1.7 編寫DAO類UserDAO.java
所謂的DAO(Data Access Object)層,就是數據訪問接口,爲了基於Hibernate的開發中,通常將業務層與數據層分開,DAO層只負責調用Hibernate API實現CRUD操作,Service層面向用戶負責調用DAO層的代碼。這樣做的好處是,數據層的代碼不用關心業務,可以更好地實現移植
下面編寫一個DAO類UserDAO.java,該類實現一個getUser()函數,根據用戶名username查詢一個用戶對象。
public class UserDAO { public User getUser(String username)throws HibernateException{ Session session=null; Transaction tx=null; User user=null; try{ session=HibernateSessionFactory.currentSession(); tx=session.beginTransaction(); Query query=session.createQuery("from User where username=?"); query.setString(0, username.trim()); user=(User)query.uniqueResult(); query=null; tx.commit(); }catch(HibernateException e){ throw e; }finally{ if(tx!=null){ tx.rollback(); } HibernateSessionFactory.closeSession(); } return user; } }
1.8 編寫Service類並運行
即服務層,就是面向用戶服務,它定義的方法都是與實際的業務相關的。
下面定義一個Service類UserService,它有一個函數valid(),根據用戶名和密碼來判斷用戶是否存在。
運行出錯
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645) at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:247) at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:284) at javax.naming.InitialContext.getNameParser(InitialContext.java:439) at org.hibernate.util.NamingHelper.bind(NamingHelper.java:52) at org.hibernate.impl.SessionFactoryObjectFactory.addInstance(SessionFactoryObjectFactory.java:90) at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:306) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294) at com.demo.hibernate.util.HibernateSessionFactory.currentSession(HibernateSessionFactory.java:19) at com.demo.hibernate.dao.UserDAO.getUser(UserDAO.java:16) at com.demo.hibernate.service.UserService.valid(UserService.java:8) at com.demo.hibernate.service.UserService.main(UserService.java:19)
原因:配置文件在存在<session-factory name="foo">,將name="foo"去掉即可
1.9 Hibernate核心類用法
1.9.1 使用Configuration裝載配置
使用hibernate.cfg.xml,該文件中設置了數據庫連接的屬性和hbm.xml映射文件配置,Hibernate會自動加載該配置屬性,並自動找到POJO類。
Configuration cfg=new Configuration();
Cfg.configure("hibernate.cfg.xml");
1.9.2 sessionFatcory
sessionFaction=cfg.buildSessionFactory();
1.9.3 Session
主要功能是提供對映射的實體類實例的創建、讀取和刪除操作。實例可能以下面3種狀態存在。
自由狀態(transient):不曾進行持久化,未與任何Session相關聯
持久化狀態(persistent):僅與一個Session相關聯
遊離狀態(detached):已經進行過持久化,但當前未與任何Session相關聯
1、 Save()保存對象
用於將一個新實例化的對象持久化,保存到數據庫中
如:session.save(user);
2、 Load()裝載對象
如果你知道某個實例的持久化標識,就可以使用Session的load()方法來獲取它。
如:User user=(User)session.load(User.class,new Integer("1"));
表示加載標識符爲1的User,並賦給一個新的實例變量user。
此外,你可以把數據加載到指定的對象實例上(覆蓋該實例原來的數據)
Session.load(user,new Integer("1"));(如果沒有匹配的數據庫記錄,load方法可能拋出無法恢復的異常unrecoverable exception)
3、 Get()裝載對象
如果你不確定是否有匹配的行記錄存在,應該使用get()方法,它會立刻訪問數據庫,如果沒有,會返回null。
4、 Flush()強制提交刷新
如果一個實例被更改了,則可以使用flush()將更改後的實例對象強制保存到數據庫中。
5、 Update()提交遊離狀態的對象
6、 Delete()移除持久化對象
該函數用於從數據庫中刪除對象對應的記錄
7、 Refresh()強制裝載對象
任何時候都可以使用refresh()方法強迫裝載對象和它的集合。如果你使用數據庫觸發器功能來處理對象的某些屬性,這個方法就很有用了。
1.9.4 使用Transaction管理事務
Transaction tx=session.begionTransaction();
…
Tx.commit();
1.9.5 使用Query進行HQL查詢
1、 不帶參數的查詢
Query query=session.createQuery(“from user”);
2、 帶參數的查詢
接口Query提供了對命名參數、JDBC風格的問號(?)參數兩種參數綁定方法。
如:
Query query=session.createQuery("from User where username=:username");
query.setString("username","admin")
也可以使用集合型參數。如下所示,在SQL語句中使用in關鍵字指向一個命名參數列表
List names=new ArrayList();
names.add(admin);
names.add(test);
Query query=session.createQuery("from user where username in (:nameList)");
query.setParameterList("nameList",names);
3、 使用問號參數
Query query=session.createQuery("from user where username=?");
query.setString(0,"admin");
4、 取得List結果集
List list=query.list();
5、 取得迭代列表結果集
Iterate()
6、 取得一個對象
如果你知道當前查詢只會返回一個對象,則可使用list()的快捷方式uniqueResult()來取得一個對象
User user=(User)query.uniqueResult()
7、 標量查詢
查詢可以在select從句中指定類的屬性,甚至可以調用SQL統計函數
Iterator results=session.createQuery(
"Select user.username,count(user.email) from user group by username")
.list().iterator;
8、 分頁查詢
query.setFirstResult(10);//設置起始範圍
query.setMaxResults(20);//設置結束範圍
List list=query.list();
9、 創建SQL查詢
可以使用createSQLQuery()方法,用普通的SQL來描述查詢並由Hibernate處理將結果貪集轉換成對象的工作。
List users=session.createSQLQuery(SELECT {user}.* FROM User {user}).list();
其中SQL別名需要用大括號包圍起來。和Hibernate查詢一樣,SQL查詢也可以包含命名參數和佔位參數
1.9.6 使用Criteria進行條件查詢
Criteria接口與Query接口非常類似,它允許你創建並執行面向對象的標準化查詢。動態地使用面向對象API創建查詢,而非在Java代碼中嵌入字符串
創建Criteria實例
Cirteria criteria=session.createCriteria(User.class);
Criteria.setMaxResults(50);
List users=criteria.list();
1、 添加查詢條件
查詢條件是通過org.hibernate.criterion.Restrictions類來實現的,用來模擬SQL語句中的條件關鍵字,例如like、between、and、or等
Criteria criteria=session.createCriteria(User.class);
criteria.add(Restrictions.like("username","admin%"));
criteria.add(Restrictions.between("ID",1,10));
List users=criteria.list();
2、 添加排序條件
可以使用org.hibernate.criterion.Order來爲查詢結果排序,它共包含兩個方法,asc()和desc(),分別實現SQL語句中的asc和desc關鍵字。通過調用Criteria的addOrder()來添加多個Order實例,如下
List users=session.createCriteria(User.class)
.add(Restrictions.like("username","admin%"))
.addOrder(Order.asc("username"))
.addOrder(Order.asc("password"))
.list();
3、 示例查詢
Org.hibernate.criterion.Example類允許通過一個給定實例來構建一個條件查詢。
User user=new User();
User.setUsername();
List results=session.createCriteria(User.class)
.add(Example.create(user)).list();