一、Hibernate 的 CRUD 基本操作
// 取得 session ,通常我們利用 hibernate.cfg.xml 的配置
// 以用戶表和部門為例
Configuration config = new Configuration().configure();
SessionFactory sessionFactory =
config.buildSessionFactory();
Session session = sessionFactory.openSession();
(1) 查詢數據
// 取所有記錄
Criteria criteria = session.createCriteria(User.class);
Query query = session. createQuery ;
List resultList = criteria.list()/ query . list();
// 按條件查詢
Query query = session .createQuery("from User where id between :ID1 and :ID2");
query.setInteger("ID1",0);
query.setInteger("ID2",2);
Criteria criteria = getSession().createCriteria(User.class);
criteria.add(Restrictions.eq("id",new Integer(1)));
// 更復查的查詢見 Criteria 詳解
(2) 插入記錄
// 不設關聯的時候,可以直接 save 一個對象
User user = new User();
user.setUserName(“jiangliwen”);
user.setSex(“ 男 ”);
session.save(user);
(3) 刪除記錄
// 把一個 POJO 變成 PO 后就可以刪除,不過有時候方法會在刪除的時候自動變為 PO
// 當你發現 User user = new User(New Integer(1)), 出錯的時候,說明不行
User user = (User)session.load(User.class,new Integer(1));
session.delete(user);
(4) 更新記錄
// 過程為取出、修改、保存
User user = (User)session.load(User.class,new Integer(1));
user.setRealName(“ 哈哈 ”);
session.update(user);
二、Criteria 查詢總結,能完成一般查詢、統計、分組、多表查詢
填入任一查詢參數,模糊查詢
Criteria criteria = getSession().createCriteria(User.class);
criteria.add(Restrictions.eq("id",new Integer(1)));
List list = criteria.list();
criteria.add(Restrictions. like("username",”%jiang%”));
您可以使用 Criteria 進行查詢,並使用 Order 對結果進行排序,例如使用 Oder.asc() 由小到大排序
(反之則使用 desc() ):
Criteria criteria = session.createCriteria(User.class);
criteria.addOrder(Order.asc("age"));
List users = criteria.list();
setMaxResults() 方法可以限定查詢回來的筆數,如果配合 setFirstResult() 設定傳回查詢結果
第一筆資料的位置,就可以實現簡單 的分頁,例如傳回第 51 筆之後的 50 筆資料(如果有的話):
Criteria criteria = session.createCriteria(User.class);
criteria.setFirstResult(51);
criteria.setMaxResult(50);
List users = criteria.list();
您可以對查詢結果進行統計動作,使用 Projections 的 avg() 、 rowCount() 、 count() 、 max() 、 min() 、
countDistinct() 等方法,例如對查詢結果的 "age" 作平均:
Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(Projections.avg("age"));
List users = criteria.list();
Iterator iterator = users.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
還可以配合 Projections 的 groupProperty() 來對結果進行分組,例如以 "age" 進行分組,也就是如果資料中 "age"
如果有 20 、 20 、 25 、 30 ,則以下會顯示 20 、 25 、 30 :
Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(Projections.groupProperty("age"));
List users = criteria.list();
Iterator iterator = users.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
如果想結合統計與分組功能,則可以使用 ProjectionList ,例如下面的程式會計算每個年齡各有多少個人:
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("age"));
projectionList.add(Projections.rowCount());
Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(projectionList);
List users = criteria.list();
Iterator iterator = users.iterator();
while(iterator.hasNext()) {
Object[] o = (Object[]) iterator.next();
System.out.println(o[0] + "\t" + o[1]);
}
如果有一個已知的物件,則可以根據這個物件作為查詢的依據,看看是否有屬性與之類似的物件,例如:
User user = new User();
user.setAge(new Integer(30));
Criteria criteria = session.createCriteria(User.class);
criteria.add(Example.create(user));
List users = criteria.list();
Iterator iterator = users.iterator();
System.out.println("id \t name/age");
while(iterator.hasNext()) {
User ur = (User) iterator.next();
System.out.println(ur.getId() +
" \t " + ur.getName() +
"/" + ur.getAge());
}
在這個例子中, user 物件中有已知的屬性 "age" 為 30 ,使用 Example 會自動過濾掉 user 的空屬性,
並以之作為查詢的依據,也就是找出 "age" 同為 30 的資料。
Criteria 可以進行複合查詢,即在原有的查詢基礎上再進行查詢,例如在 Room 對 User 的一對多關聯中,
在查詢出所有的 Room 資料之後,希望再查詢 users 中 "age" 為 30 的 user 資料:
Criteria roomCriteria = session.createCriteria(Room.class);
Criteria userCriteria = roomCriteria.createCriteria("users");
userCriteria.add(Restrictions.eq("age", new Integer(30)));
List rooms = roomCriteria.list(); // 只列出 users 屬性中有 user 之 "age" 為 30 的 Room
Iterator iterator = rooms.iterator();
三、Hibernate 的事務管理
Hibernate 是 JDBC 的輕量級封裝,本身并不具備事務管理能力。在事務管理層,
Hibernate 將其委托給底層的 JDBC 或者 JTA ,以實現事務管理和調度功能。
Hibernate 的默認事務處理機制基于 JDBC Transaction 。我們也可以通過配置文
件設定采用 JTA 作為事務管理實現:
< property name = "hibernate.transaction.factory_class" >
net.sf.hibernate.transaction.JTATransactionFactory
<!--net.sf.hibernate.transaction.JDBCTransactionFactory-->
</ property >
基于 JDBC 的事務管理
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
……
tx.commit();
從 JDBC 層面而言,上面的代碼實際上對應著:
Connection dbconn = getConnection();
dbconn.setAutoCommit( false );
……
dbconn.commit();
基于 JTA 的事務管理
JTA 提供了跨 Session 的事務管理能力。這一點是與 JDBC Transaction 最大的
差異。
JDBC 事務由 Connnection 管理,也就是說,事務管理實際上是在 JDBC Connection
中實現。事務周期限于 Connection 的生命周期之類。同樣,對于基于 JDBC Transaction
的 Hibernate 事務管理機制而言,事務管理在 Session 所依托的 JDBC Connection
中實現,事務周期限于 Session 的生命周期。
JTA 事務管理則由 JTA 容器實現, JTA 容器對當前加入事務的眾多 Connection 進
行調度,實現其事務性要求。 JTA 的事務周期可橫跨多個 JDBC Connection 生命周期。
同樣對于基于 JTA 事務的 Hibernate 而言, JTA 事務橫跨可橫跨多個 Session 。
因此當 open 多個 session 時候,用 JTA 來管理事務。
在 EJB 中使用 JTA Transaction 無疑最為簡便,我們只需要將 save 方法配置為
JTA 事務支持即可,無需顯式申明任何事務,下面是一個 Session Bean 的 save 方法,
它的事務屬性被申明為“ Required ”, EJB 容器將自動維護此方法執行過程中的事務:
Hibernate 支持兩種鎖機制:即通常所說的“悲觀鎖( Pessimistic Locking )”
和“樂觀鎖( Optimistic Locking )”
悲觀鎖:保守態度,一旦上鎖,外界無法修改,直到釋放
樂觀鎖: Hibernate 在其數據訪問引擎中內置了樂觀鎖實現。如果不用考慮外部系統對數
據庫的更新操作,利用 Hibernate 提供的透明化樂觀鎖實現,將大大提升我們的
生產力。
< class
name = "org.hibernate.sample.TUser"
table = "t_user"
dynamic-update = "true"
dynamic-insert = "true"
optimistic-lock = "version"
>
樂觀鎖,大多是基于數據版本
( Version )記錄機制實現。
Cache 管理
使用 cache 的目的往往是為了提高系統的性能;
引入 Cache 機制的難點是如何保證內存中數據的有效性,否則臟數據的出現將給系統
帶來難以預知的嚴重后果。
Hibernate 中的 Cache 大致分為兩層,第一層 Cache 在 Session 實現,屬于事務
級數據緩沖,一旦事務結束,這個 Cache 也就失效。
第二層 Cache ,是 Hibernate 中對其實例范圍內的數據進行緩存的管理容器。
我們需要討論的是第二層 Cache, 最簡單是基于 HashTable 的 cache 機制 .
使用了 Cache 機制之后,應當注意編碼的結合,特別在查詢數據的時候使用:
Query.list(); 取出所有的數據 , 一次 sql
Query.iterate(); 兩次 sql, 一次去 ID , 如果有 cache 則優先查找,二次才取數據
Session 管理
SessionFactory 負責創建 Session , SessionFactory 是線程
安全的,多個并發線程可以同時訪問一個 SessionFactory 并從中獲取 Session 實例。而
Session 并非線程安全,也就是說,如果多個線程同時使用一個 Session 實例進行數據存取,
則將會導致 Session 數據存取邏輯混亂。
我們可以通過應用 ThreadLocal 機制 , 來維持一個 session
public class HibernateUtil {
private static SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory
sessionFactory = new
Configuration().configure().buildSessionFactory();
} catch (HibernateException ex) {
throw new RuntimeException(
"Configuration problem: " + ex.getMessage(),
ex
);
}
}
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException
{
Session s = (Session) session.get();
// Open a new Session, if this Thread has none yet
if (s == null ) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set( null );
if (s != null )
s.close();
}
}
對于 web 程序而言
我們可以借助 Servlet2.3 規范中新引入的 Filter 機制,輕松實現線程生命周期內的 Session 管理
四、再度思考
1 、對 ORM 的理解
ORM ( Object Relational Mapping )簡單的說,就是對象與關系的映射,對于實際應用來講,
對象一般指面向對象中的對象,關系指關系型數據庫,對于我們具體的項目來說,就是將 java 中的
對象與關系型數據庫( oracle , mysql )中的表聯系起來。
ORM 解決方案有以下四部分組成:
■ 在持續類的對象上執行基本的 CRUD 操作的一組 API 。
■ 用于指定查詢的一種語言或一組 API ,這些查詢會引用類和類屬性。
■ 用于指定映射元數據的工具。
■ 實現 ORM 的一項技術,用來與事務對象交互以完成臟檢查、懶關聯存取和其它優化功能。
ORM 這種解決方案的好處:
對底層的封裝,因此,可移植性好,廠商獨立;
解決對象 - 關系不匹配問題;
在傳統我們在持久層通常使用 SQL 和 JDBC ,通常認為這樣方式已經讓大家感到厭倦了,特別是煩瑣的代碼;
2 、 hibernate 可以認為是最優秀的 ORM 工具
Hibernate 是一個雄心勃勃的項目,它的目標是成為 Java 中管理持續性數據問題的一種完
整的解決方案。它協調應用與關系數據庫的交互,讓開發者解放出來專注于手中的業務問題。
Hibernate 符合 java 編程習慣,它把數據庫與一個 POJO (簡單 Java 對象)關聯起來,
使得對數據庫進行 CRUD 等操作時候,直接操作 Java 對象就可以了。通過以前 Java Bean 一樣 ,
使用 setter 和 getter 方法。
五、輔助工具
(1)自動生成 hibernate 的映射文件
一般考慮兩個方向:從數據庫到映射文件,從 java 類到映射文件
數據庫到映射文件可以采用 Middlegen-Hibernate ,這個能很直觀的看到表之間的關系,并且能適當的做修改;
從 java 類到映射文件的生成,可以用 XDoclet ,不過需要在 java 類中加上一些標記
從生成的映射文件自動生成 java 類,可以用用一些工具,如 hbm2java
從這四種自動生成工具來看, mapping file, java file and DDL ,只要知道任何一種文件,都可以得到另外兩種文件,
如:
1. 只有 mapping file:
mapping file---hbm2java----java---SchemaExport----DDL
2. 只有 DDL
DDL---Middlegen---hbm----hbm2java----java
3. 只有 Java
java---XDoclet---hbm----SchemaExport----DDL
從這里,大家也可以體會到 , Hibernate 強大的靈活性
不過我們通常習慣專門的工具設計數據庫,譬如 power designer 等工具,會自動生成 DDL ,
所以我們更需要通過 DDL ,就自動生成 Mapping file 和 java 類
(2)在 Eclipse 開發工具中,有一個比較好用的插件
Hibernate Synchronizer
? 自動生成基本的 Hibernate 配置文件
? 自動由表結構生成 POJO 類, XML Mapping 和基本的 DAO 類。
? 精巧的繼承結構將自動生成代碼和用戶定制的代碼巧妙的分割開來。
? 將自動生成的代碼放在基類( Base* )中,將用戶定制的代碼放在子類中。分割了自動生成的代碼和用戶定制的代碼。
? 當表結構發生了變化時,插件只需要更改自己生成的基類,不用管用戶定制的子類。用戶定制的子類幾乎不用改動,
或只需要很少的改動即可適應新的表結構。
另:在 hibernate 使用一個 sessionFactory 操作多個數據庫時候,可以使用
public StatelessSession openStatelessSession(Connection connection); 方法
--------------------------------------------------------------------------------------
路漫漫兮其修遠兮,吾將上下而求索!
不過對于hibernate的學習暫且告一段落,哈哈!