引導目錄:
康姆昂,北鼻,來此狗。動次打次,Hibernate繼續走起、
目錄:
為工程准備了Hibernate環境后,就可以通過Hibernate API操縱數據庫。Hibernate內部也是采用JDBC來訪問數據庫的。
如下圖就是JDBC API及Hibernate API方式來訪問數據庫:
使用Hibernate操作數據庫包括7個步驟:
(1)讀取並解析配置文件
Configuration cfg = new Configuration().configure();
根據默認位置的Hibernate配置文件的配置信息,構建Configuration對象。
Configuration負責管理Hibernate的配置信息。
(2)讀取並解析映射信息,創建SessionFactory對象:
SessionFactory sessionFactory = cfg.buildSessionFactory();
SessionFactory負責創建Session對象。
Configuration對象會根據當前的數據庫配置信息,構造SessionFactory對象。
SessionFactory對象一旦構造完畢,則Configuration對象的任何變更將不會影響已經創建的SessionFactory對象。
如果Hibernate配置信息有改動,那么需要基於改動后的Configuration對象重新構建一個SessionFactory對象。
(3)打開Session:
Session session = sessionFactory.openSession(); // 或者使用 sessionFactory.getCurrentSession();
Session是Hibernate持久化操作的基礎。Session負責完成對象的持久化操作,它相當於JDBC中的Connection。
Session作為貫穿Hibernate的持久化管理器的核心,提供了眾多持久化方法,如save()、delete()、update()、get()、load()等。
通過這些方法,即可透明地完成對象的增刪改查(CRUD)。
(4)開始一個事務(增刪改操作必須,查詢操作可選):
Transaction transaction = session.beginTransaction(); // 打開事務
(5)數據庫操作:
session.save(obj); // 將obj對象進行保存操作
(6)結束事務:
transaction.commit(); // 提交事務
(7)關閉session:
session.close(); // 關閉session
如果在Hibernate配置文件中,參數current_session_context_class設置為thread,並采用SessionFactory的getCurrentSession()方法獲得Session對象,則不需要執行session.close()方法。
資料:
在項目開發過程中,通常使用工具類來管理SessionFactory和Session,代碼如下所示:
HibernateUtil.java (Hibernate工具類)1 package com.geeksss.HibernateStudy.util; 2 3 import org.hibernate.Session; 4 import org.hibernate.SessionFactory; 5 import org.hibernate.cfg.Configuration; 6 7 public class HibernateUtil { 8 // 初始化一個ThreadLocal對象,ThreadLocal對象有get()、set()方法 9 private static final ThreadLocal sessionTL = new ThreadLocal(); 10 private static Configuration configuration; 11 private static final SessionFactory sessionFactory; 12 static{ 13 try{ 14 configuration = new Configuration().configure(); 15 sessionFactory = configuration.buildSessionFactory(); 16 }catch(Throwable ex){ 17 ex.printStackTrace(); 18 throw new ExceptionInInitializerError(ex); 19 } 20 } 21 public static Session currentSession(){ 22 /* 23 * sessionTL的get()方法根據當前縣城返回其對應的線程內部變量,即Session對象。 24 * 多線程情況下共享數據庫連接是不安全的。 25 * ThreadLoca保證了每個線程都有自己獨立的Session對象。 26 */ 27 Session session = (Session)sessionTL.get(); 28 /* 29 * 如果session為null,則打開一個新的session 30 * 如果該線程是初次訪問,session是null,則創建一個Session對象 31 */ 32 if(session==null){ 33 session = sessionFactory.openSession(); // 創建一個Session對象 34 sessionTL.set(session); // 保存該Session對象到ThreadLocal中 35 } 36 return session; // 如果當前線程已經訪問過數據庫,則從sessionTL中get()就可以獲取該線程上次獲取過的Session對象。 37 } 38 /** 39 * 關閉session 40 * 首先調用sessionTL.get()方法獲取Session對象; 41 * 接着調用sessionTL.set(null)方法,把sessionTL管理的Session對象置為null; 42 * 最后關閉Session。 43 */ 44 public static void closeSession(){ 45 Session session = (Session)sessionTL.get(); 46 sessionTL.set(null); 47 session.close(); 48 } 49 }
通過ThreadLocal類,既實現了多線程並發,同時,也實現了Singleton單例模式。
1. 使用Hibernate實現按主鍵查詢
在進行修改或刪除操作時,應先加載對象,然后再執行修改或刪除操作。
Hibernate提供了兩種方法按照主鍵加載對象:get()和load()方法、
- Object get(Class clazz, Serializable id)。
- Object load(Class theClass, Serializable id)。
雖然兩個方法都能夠加載對象,但是他們是有區別的。
下面以部門表為例,通過兩段代碼講解他們的區別:
(1) get()方法加載部門對象的代碼如下:

1 package com.geeksss.HibernateStudy.test; 2 3 import org.hibernate.HibernateException; 4 import org.hibernate.Session; 5 import org.hibernate.SessionFactory; 6 import org.hibernate.cfg.Configuration; 7 8 import com.geeksss.HibernateStudy.entity.Dept; 9 import com.geeksss.HibernateStudy.entity.Users; 10 import com.geeksss.HibernateStudy.util.HibernateUtil; 11 12 public class Test { 13 public static void main(String[] args) { 14 15 Configuration cfg = null; 16 SessionFactory sessionFactory = null; 17 Session session = null; 18 19 try { 20 // 讀取配置文件 21 cfg = new Configuration().configure(); 22 // 創建SessionFactory 23 sessionFactory = cfg.buildSessionFactory(); 24 // 打開session; 25 session = sessionFactory.openSession(); 26 // 加載數據操作 27 Users user = (Users)session.get(Users.class, new Integer("4")); 28 // 輸出操作 29 System.out.println("使用get()方式獲取id為4的用戶是:"+user.getName()); 30 } catch (HibernateException e) { 31 e.printStackTrace(); 32 }finally{ 33 if(null!=session){ 34 session.close(); 35 } 36 } 37 38 } 39 }
運行效果如圖:
(2) load()方法加載數據,只需要將get換為load即可,結果不變。如圖:
到此,可能大家肯定會想,為什么查詢一個數據,會有兩種方式呢?
希望大家明白:學一個東西,不管是什么,既然存在,那么就有它存在的意義。
get()和load()亦是如此,肯定有區別的啊~下面我們來演示看一下。。。
現在我的數據庫中,User表中只有4條記錄:
下面我們分別使用get()和load()獲取id為10的對象並輸出,看一下結果。
1.get()方式,查詢返回null:
2.load()方式,查詢返回如下異常:
異常信息為: org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.geeksss.HibernateStudy.entity.Users#10]
即:對象未找到。
由此,我們得知:
當使用Session的get()方法時,如果加載的數據不存在,get()方法會返回一個null;但是使用load()方法,若加載的數據不存在,則會拋出異常。
這是get()方法和load()方法的區別之一,兩個方法的其他區別,我們后面會慢慢講到。
2. 使用Hibernate實現數據庫的增、刪、改操作
2.1 使用Hibernate實現增加用戶記錄
增加操作的測試代碼如下:
1 package com.geeksss.HibernateStudy.test; 2 3 import org.hibernate.HibernateException; 4 import org.hibernate.Session; 5 import org.hibernate.SessionFactory; 6 import org.hibernate.Transaction; 7 import org.hibernate.cfg.Configuration; 8 9 import com.geeksss.HibernateStudy.entity.Users; 10 11 public class Test { 12 public static void main(String[] args) { 13 Configuration cfg = null; 14 SessionFactory sessionFactory = null; 15 Session session = null; 16 Transaction transaction = null; 17 18 Users user = new Users(); // 實例化一個對象 並賦值 19 user.setName("李四"); 20 user.setPassword("ls123456"); 21 user.setTelephone("13800138000"); 22 user.setUsername("lisi"); 23 user.setisAdmin(false); 24 25 try { 26 cfg = new Configuration().configure(); // 讀取配置文件 27 sessionFactory = cfg.buildSessionFactory(); // 創建SessionFactory 28 session = sessionFactory.openSession(); // 打開session; 29 transaction = session.beginTransaction(); // 開啟一個事務 30 session.save(user); // 持久化操作 31 transaction.commit(); // 提交事務 32 } catch (HibernateException e) { 33 e.printStackTrace(); 34 transaction.rollback(); // 回滾事務 35 }finally{ 36 if(null!=session) session.close(); // 關閉session 37 } 38 39 } 40 }
與JDBC一樣,持久化操作放在try中,如果正常則提交,如果異常則進入catch回滾,最后關閉session。
不過,運行出現異常,結果如下:
仔細觀察,我們發現,在控制台中,插入的SQL語句正確打印,但是出錯,錯誤信息顯示:“當 IDENTITY_INSERT 設置為 OFF 時,不能為表 'Users' 中的標識列插入顯式值。”
很明顯,在這里我們插入數據的時候,並沒有通過user.setId(xxx)來為其設置編號,那么也就是默認的0。
打開Users.hbm.xml映射文件,我們發現主鍵的生成策略我們設置的是“assigned”,也就是由應用程序控制,不用Hibernate干涉。(上節介紹過)
而在這里,我們SQL Server中的Users主鍵是自動增長的,因此,我們設置為“identity”(自增)或“native”(自動識別)都是可以的。
設置完映射文件的代碼如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 6 <hibernate-mapping package="com.geeksss.HibernateStudy.entity"> 7 <class name="Users" table="Users"> 8 <id name="id" type="java.lang.Integer" column="Id"> 9 <generator class="identity"></generator> 10 </id> 11 <property name="name" type="java.lang.String" column="Name"></property> 12 <property name="password" type="java.lang.String" column="Password"></property> 13 <property name="telephone" type="java.lang.String" column="Telephone"></property> 14 <property name="username" type="java.lang.String" column="Username"></property> 15 <property name="isAdmin" type="java.lang.Boolean" column="IsAdmin"></property> 16 </class> 17 </hibernate-mapping>
再次運行程序,插入成功:
2.2 使用Hibernate實現用戶信息的修改、刪除
下面學習如何使用Hibernate修改和刪除數據。
對於Hibernate這種ORM工具,操作都是針對對象的。
要修改和刪除數據,首先要獲得數據,然后再進行修改和刪除數據。
2.2.1 使用Hibernate修改用戶數據
實例代碼如下:

1 package com.geeksss.HibernateStudy.test; 2 3 import org.hibernate.HibernateException; 4 import org.hibernate.Session; 5 import org.hibernate.SessionFactory; 6 import org.hibernate.Transaction; 7 import org.hibernate.cfg.Configuration; 8 9 import com.geeksss.HibernateStudy.entity.Dept; 10 import com.geeksss.HibernateStudy.entity.Users; 11 import com.geeksss.HibernateStudy.util.HibernateUtil; 12 13 public class Test { 14 public static void main(String[] args) { 15 16 Configuration cfg = null; 17 SessionFactory sessionFactory = null; 18 Session session = null; 19 Transaction transaction = null; 20 try { 21 cfg = new Configuration().configure(); // 讀取配置文件 22 sessionFactory = cfg.buildSessionFactory(); // 創建SessionFactory 23 session = sessionFactory.openSession(); // 打開session; 24 25 Users user = (Users)session.get(Users.class, new Integer("4")); // 加載數據操作 26 System.out.println("修改之前編號4用戶姓名是:"+user.getName()); // 輸出操作 27 28 transaction = session.beginTransaction(); // 創建事務 29 user.setName("測試修改"); // 修改對象 30 transaction.commit(); // 提交事務 完成修改 31 32 user = (Users)session.get(Users.class, new Integer("4")); // 重新加載數據 33 System.out.println("修改之后編號4用戶姓名是:"+user.getName()); // 輸出操作 34 } catch (HibernateException e) { 35 e.printStackTrace(); 36 if(null != transaction){ 37 transaction.rollback(); 38 } 39 }finally{ 40 if(null!=session){ 41 session.close(); 42 } 43 } 44 45 } 46 }
執行結果如下:
在使用Hibernate修改數據時,首先要加載對象,然后修改對象的屬性,最后提交事務。
Hibernate會生成並執行修改的SQL語句,其中的原理會在后面慢慢講到滴~
2.2.2 使用Hibernate實現刪除Users數據
實例代碼如下:

1 package com.geeksss.HibernateStudy.test; 2 3 import org.hibernate.HibernateException; 4 import org.hibernate.Session; 5 import org.hibernate.SessionFactory; 6 import org.hibernate.Transaction; 7 import org.hibernate.cfg.Configuration; 8 9 import com.geeksss.HibernateStudy.entity.Dept; 10 import com.geeksss.HibernateStudy.entity.Users; 11 import com.geeksss.HibernateStudy.util.HibernateUtil; 12 13 public class Test { 14 public static void main(String[] args) { 15 16 Configuration cfg = null; 17 SessionFactory sessionFactory = null; 18 Session session = null; 19 Transaction transaction = null; 20 try { 21 cfg = new Configuration().configure(); // 讀取配置文件 22 sessionFactory = cfg.buildSessionFactory(); // 創建SessionFactory 23 session = sessionFactory.openSession(); // 打開session; 24 25 Users user = (Users)session.get(Users.class, new Integer("4")); // 加載數據操作 26 System.out.println("刪除之前編號4用戶是:"+user); // 輸出操作 27 28 transaction = session.beginTransaction(); // 創建事務 29 session.delete(user); // 刪除user對象 30 transaction.commit(); // 提交事務 完成刪除 31 32 user = (Users)session.get(Users.class, new Integer("4")); // 重新加載數據 33 System.out.println("刪除之后編號4用戶是:"+user); // 輸出操作 34 } catch (HibernateException e) { 35 e.printStackTrace(); 36 if(null != transaction){ 37 transaction.rollback(); 38 } 39 }finally{ 40 if(null!=session){ 41 session.close(); 42 } 43 } 44 45 } 46 }
執行結果如下:
與修改類似,刪除時也需要先加載數據。
在使用Hibernate編寫持久化代碼時,業務不需要再有數據庫表、字段等概念。
從面相業務領域對象的角度,要刪除的是某個業務對象。以面相對象的方式編寫的代碼是Hibernate持久化操作接口設計的一個理念。
需要注意的是,增、刪、改操作一定要在事務環境中完成。
3. 技能訓練 - 在租房網系統中實現用戶表的增刪改查操作
在上一節我們已經搭建好的Hibernate環境中,使用Hibernate實現用戶記錄的增加、修改、刪除和查詢操作。
要求按照用戶編號查詢指定的用戶記錄。
同志們,有錯提錯,代碼擼起吧~ 呵呵。