Hibernate的系統 學習

Hibernate的系統 學習html

1、Hibernate的介紹java

 

1.什麼是Hibernate?

          首先,hibernate是數據持久層的一個輕量級框架。數據持久層的框架有不少好比:iBATIS,myBatis,Nhibernate,Siena等等。node

          而且Hibernate是一個開源的orm(object relations mapping)框架,提供了查詢獲取數據的方法,用面向對象的思想來操做數據庫,節省了咱們開發處理數據的時間。mysql

2.那使用Hibernate的優勢呢?算法

          1.使用簡介的hql語句(Hibernate query language)。能夠不使用傳統的insert,update等sql語句。好比insert一個對象,原來的作法是:insert into 表名稱 alue(值1,值2,值3,……),而如今的作法是:save(對象)。sql

          2.使用or映射。對象到關係數據庫之間的映射。是從對象的角度操做數據庫,再次體現了面向對象思想。原來的實體抽取方法:首先有了表,而後表映射實體對象。而如今Hibernate作法是:直接由對象映射到表。數據庫

          3.沒有侵入性,移植性比較好。什麼是沒有侵入性?就是Hibernate採用了pojo對象。所謂的pojo對象就是沒有繼承Hibernate類或實現Hibernate接口。這樣的話,此類就是一個普通的Java類,因此移植性比較好。  數組

         4.支持透明持久化。透明是針對上層而言的。三層架構的理念是上層對下層的依賴,只是依賴接口不依賴具體實現。而Hibernate中的透明是指對業務邏輯層提供了一個接口session,而其餘的都封裝隱藏。持久化是指把內存中的數據存放到磁盤上的文件中。緩存

3.固然一個事物,不可能十全十美,即便如此優秀的Hibernate也有本身的弱點。好比:如果大量數據批量操做。則不適合使用Hibernate。而且一個持久化對象不能映射到多張表中。tomcat

4.Hibernate中核心5個接口

       1.Configuration接口:負責配置及啓動Hibernate,用來建立sessionFactory

       2.SessionFactory接口:一個SessionFactory對應一個數據源存儲,也就是一個數據庫對應一個SessionFactory。SessionFactory用來建立Session對象。而且SessionFactory是線程安全的,能夠由多個線程訪問SessionFactory共享。

       3.Session接口:這個接口是Hibernate中經常使用的接口,主要用於對數據的操做(增刪改查)。而這個Session對象不是線程安全的。不能共享。

       4.Query接口:用於數據庫的查詢對象。

       5.Transaction接口:Hibernate事務接口。它封裝了底層的事務操做,好比JTA(;Java transcation architecture)全部的數據操做,好比增刪改查都寫在事務中。

基本的概念以及核心接口已經介紹,那Hibernate又是如何應用的呢?下篇博客將會介紹如何使用Hibernate?

  2、詳解Hibernate的搭建及使用
  

 1.建立普通的Java項目。

               由於hibernate是一個輕量級的框架,不像servlet,還必須須要tomcat的支持,Hibernate只要jdk支持便可。

       2.引入jar包。

               能夠在項目中直接引入jar包,在:項目--->屬性--->而後以下圖:

              另外一種辦法就是引入庫,至關於一個文件夾,把全部的jar包放到本身新建的文件夾中。在:窗體-->選項-->而後以下圖:

      3.提供Hibernate的配置文件。hibernate.cfg.xml文件。完成相應的配置。

   

    

[html]  view plain  copy
 
 print?
  1. <hibernate-configuration>  
  2.   
  3. <session-factory>  
  4.   
  5. <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>  
  6.   
  7. <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_first</property>  
  8.   
  9. <property name="hibernate.connection.username">root</property>  
  10.   
  11. <property name="hibernate.connection.password">bjpowernode</property>  
  12.   
  13. <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>  
  14.   
  15. </session-factory>  
  16.   
  17. </hibernate-configuration>  


 

      在這裏鏈接MySQL數據庫,解釋一下上面的標籤。按照順序來依次解釋:第一個是鏈接mySql的驅動;第二個是鏈接的url;url後面的hibernate_first是數據庫名字;第三個是和第四個分別是用戶名和密碼。第五個是方言。由於 hibernate對數據庫封裝,對不一樣的數據庫翻譯成不一樣的形式,好比drp中的分頁,如果使用Oracle數據庫,則翻譯成sql語句三層嵌套。如果使用mySql數據庫,則翻譯成limit語句。

    4.創建實體User類:

[java]  view plain  copy
 
 print?
  1. package com.bjpowernode.hibernate;  
  2.   
  3. import java.util.Date;  
  4.   
  5. public class User {  
  6.   
  7.     private String id;  
  8.       
  9.     private String name;  
  10.       
  11.     private String password;  
  12.       
  13.     private Date createTime;  
  14.       
  15.     private Date expireTime;  
  16.   
  17.     public String getId() {  
  18.         return id;  
  19.     }  
  20.   
  21.     public void setId(String id) {  
  22.         this.id = id;  
  23.     }  
  24.   
  25.     public String getName() {  
  26.         return name;  
  27.     }  
  28.   
  29.     public void setName(String name) {  
  30.         this.name = name;  
  31.     }  
  32.   
  33.     public String getPassword() {  
  34.         return password;  
  35.     }  
  36.   
  37.     public void setPassword(String password) {  
  38.         this.password = password;  
  39.     }  
  40.   
  41.     public Date getCreateTime() {  
  42.         return createTime;  
  43.     }  
  44.   
  45.     public void setCreateTime(Date createTime) {  
  46.         this.createTime = createTime;  
  47.     }  
  48.   
  49.     public Date getExpireTime() {  
  50.         return expireTime;  
  51.     }  
  52.   
  53.     public void setExpireTime(Date expireTime) {  
  54.         this.expireTime = expireTime;  
  55.     }  
  56. }  


 

    5.創建User.hbm.xml,此文件用來完成對象與數據庫表的字段的映射。也就是實體類的那些字段須要映射到數據庫表中呢。 

   

[html]  view plain  copy
 
 print?
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping>  
  6.     <class name="com.bjpowernode.hibernate.User">  
  7.         <id name="id">  
  8.             <generator class="uuid"/>  
  9.         </id>  
  10.         <property name="name"/>  
  11.         <property name="password"/>  
  12.         <property name="createTime"/>  
  13.         <property name="expireTime"/>  
  14.     </class>  
  15. </hibernate-mapping>  


 

    6.咱們也映射完畢了,可是hibernate怎麼知道咱們映射完了呢,以及如何映射的呢?這就須要咱們把咱們本身的映射文件告訴hibernate,即:在hibernate.cfg.xml配置咱們的映射文件。

 

[html]  view plain  copy
 
 print?
  1. <mapping resource="com/bjpowernode/hibernate/User.hbm.xml"/>  


 

    7.生成數據庫表。你們也看到了咱們上述尚未新建數據表呢,在第三步咱們只是新建了數據庫而已。按照咱們普通的作法,咱們應該新建數據表啊,不然實體存放何處啊。這個別急,數據庫表這個確定是須要有的,這個毋庸置疑,可是這個可不像咱們原來須要本身親自動手創建哦,如今hibernate須要幫咱們實現哦,如何實現嗯,hibernate會根據配置文件hibernate.cfg.xml和咱們的映射文件User.hbm.xml會自動給咱們生成相應的表,而且這個表的名字也給咱們取好:默認是User。那如何生成表呢?

 

[java]  view plain  copy
 
 print?
  1. //默認讀取hibernate.cfg.xml文件  
  2.     Configuration cfg = new Configuration().configure();  
  3.       
  4.     SchemaExport export = new SchemaExport(cfg);  
  5.     export.create(true, true);  


 

 8.那咱們就開始進行操做啦,咱們添加一個用戶對象,看看hibernate是如何添加的呢?跟咱們之前的作法有什麼不一樣呢?

[java]  view plain  copy
 
 print?
  1. public class Client {  
  2.   
  3.     public static void main(String[] args) {  
  4.           
  5.         //讀取hibernate.cfg.xml文件  
  6.         Configuration cfg = new Configuration().configure();  
  7.           
  8.         //創建SessionFactory  
  9.         SessionFactory factory = cfg.buildSessionFactory();  
  10.           
  11.         //取得session  
  12.         Session session = null;  
  13.         try {  
  14.             session = factory.openSession();  
  15.             //開啓事務  
  16.             session.beginTransaction();  
  17.             User user = new User();  
  18.             user.setName("張三");  
  19.             user.setPassword("123");  
  20.             user.setCreateTime(new Date());  
  21.             user.setExpireTime(new Date());  
  22.               
  23.             //保存User對象  
  24.             session.save(user);  
  25.               
  26.             //提交事務  
  27.             session.getTransaction().commit();  
  28.         }catch(Exception e) {  
  29.             e.printStackTrace();  
  30.             //回滾事務  
  31.             session.getTransaction().rollback();  
  32.         }finally {  
  33.             if (session != null) {  
  34.                 if (session.isOpen()) {  
  35.                     //關閉session  
  36.                     session.close();  
  37.                 }  
  38.             }  
  39.         }  
  40.     }  
  41. }  


 

 第八步,咱們能夠看到,沒有咱們熟悉的insert into表的sql語句了,那怎麼添加進去的呢,到底添加了沒?讓我真實滴告訴你,確實添加進去了,不信的,能夠本身嘗試哦,這也是hibernate的優勢,對jdbc封裝的完全,減小了咱們對數據的操做時間哈。

 3、Hibernate的總結
  

看一下hibernate中總體的內容:

   咱們一一介紹其中的內容。

  1. Hibernate出現的緣由上篇博客已經介紹,能夠參考《Hibernate介紹》
  2. Hibernate中的核心五大接口,在上篇博客中也已經介紹,能夠參考《Hibernate介紹》
  3. 如何搭建Hibernate,請參考《八步詳解Hibernate的搭建及使用》
  4. 持久化對象的三種狀態。

分別爲:瞬時狀態(Transient),持久化狀態(Persistent),離線狀態(Detached)。三種狀態下的對象的生命週期以下:

三種狀態的區別是:瞬時狀態的對象:沒有被session管理,在數據庫沒有;持久化狀態的對象:被session管理,在數據庫存在,當屬性發生改變,在清理緩存時,會自動和數據庫同步;離線狀態:沒有被session管理,可是在數據庫中存在。

5.測試工具Juit。

測試類須要繼承TestCase,編寫單元測試方法,方法名稱必須爲test開頭,方法沒有參數沒有返回值,採用public修飾。其中在測試中,查詢對象時,使用get或者load兩種方法進行加載,這種方法的區別:get不支持延遲加載,而load默認狀況下是支持延遲加載。而且get查詢對象不存在時,返回null;而load查詢對象不存在時,則拋出ObjectNotFoundException異常。

6.悲觀鎖和樂觀鎖解釋。

悲觀鎖爲了解決併發性,跟操做系統中的進程中添加鎖的概念同樣。就是在整個過程當中在事務提交以前或回滾以前,其餘的進程是沒法訪問這個資源的。悲觀鎖的實現方式有兩種:一種使用數據庫中的獨佔鎖;另外一種是在數據庫添加一個鎖的字段。hibernate中聲明鎖以下:

Account account = (Account)session.get(Account.class, 1, LockMode.UPGRADE);而net.sf.hibernate.LockMode類表示鎖模式,當取值LockMode.UPGRADE時,則表示使用悲觀鎖for update;而樂觀鎖是爲了解決版本衝突的問題。就是在數據庫中添加version字段,每次更新時,則把本身的version與數據庫中的version進行比較,如果版本相比較低,則不容許進行修改更新。

7.H ibernate中的緩存機制。

緩存是什麼呢?緩存是應用程序和數據庫之間的內存的一片區域。主要的目的是:爲了減小對數據庫讀取的時間。當查詢數據時,首先在緩存中查詢,若存在,則直接取出,若不存在,而後再向數據庫中查詢。因此應該把常常訪問數據庫的數據放到緩存中,至於緩存中的數據如何不斷的置換,這也須要涉及一種淘汰數據的算法

談到這個hibernate中的緩存,你想到了什麼呢?剛纔敘述緩存時,是否感受很熟悉,感受從哪也聽過似的。嗯呢,是呢,是很熟悉,寫着寫着就很熟悉,這個剛纔的緩存以及緩存的置換算法就和計算機組成中的cache相似。

好吧,來回到咱們hibernate中的緩存。

hibernate中的緩存能夠分爲兩種:一級緩存,也稱session緩存;二級緩存,是由sessionFactory管理。

那一級緩存和二級緩存有什麼區別呢?區別的關鍵關於:緩存的生命週期,也就是緩存的範圍不一樣。

那首先介紹一下緩存的生命週期,也就是緩存的範圍。

1.事務緩存,每一個事務都有本身的緩存,當事務結束,則緩存的生命週期一樣結束,正如上篇博客中咱們提到,對數據庫的操做,增刪改查都是放到事務中的,和事務保持同步,如果事務提交完畢,通常是不容許是再次對數據庫進行操做。因此session是屬於事務緩存的。

2.應用緩存,一個應用程序中的緩存,也就是應用程序中的全部事務的緩存。只有當應用程序結束時,此時的緩存的額生命週期結束。二級緩存就是應用緩存。

3.集羣緩存,被一臺機器或多臺機器的進程共享。

這下明白了一級緩存和二級緩存的區別了吧。那一級緩存和二級緩存的共同點是:都是緩存實體屬性,

二級緩存通常狀況都是由第三方插件實現的。第三方插件如:

EHCache,JbossCache(是由Jboss開源組織提供的),osCache(open symphony),swarmCache。前三種對hibernate中的查詢緩存是支持的,後一種是不支持hibernate查詢緩存。

那什麼是hibernate查詢緩存呢?

查詢緩存是用來緩存普通屬性的,對於實體對象而言,是緩存實體對象的id。

8.hql查詢。

  hibernate query language。hql查詢中關鍵字不區分大小寫,可是類和屬性都是區分大小寫的。

  1.簡單屬性查詢。

  單一屬性查詢,返回屬性結果集列表,元素類型和實體類的相應的類型一致。

[java]  view plain  copy
 
 print?
  1. List students = session.createQuery("select name from Student").list();  
  2.   
  3. for (Iterator iter=students.iterator(); iter.hasNext();) {  
  4.   
  5. String name = (String)iter.next();  
  6.   
  7. System.out.println(name);  
  8.   
  9. }  


 

 //返回結果集屬性列表,元素類型和實體類中的屬性類型一致

多個屬性查詢,多個屬性查詢返回數組對象,對象數組的長度取決於屬性的個數,對象數組中的元素類型與實體類中屬性一致。

[java]  view plain  copy
 
 print?
  1. List students = session.createQuery("select id, name from Student").list();  
  2.   
  3. for (Iterator iter=students.iterator(); iter.hasNext();) {  
  4.   
  5. Object[] obj = (Object[])iter.next();  
  6.   
  7. System.out.println(obj[0] + ", " + obj[1]);  
  8.   
  9. }  


 

2.實體對象查詢

List students = session.createQuery("from Student").list();

固然這種hql語句,可使用別名,as能夠省去,如:from Student as s,如果使用select關鍵字,則必須使用別名。如:select s from Student as s.可是不支持select * from Student格式。

查詢中使用list和Iterate區別:

list查詢是直接運行查詢的結果,因此只有一句sql語句。而iterate方法則有可能會產生N+1條sql語句。這是怎麼回事呢?要理解N+1條語句,首先得弄明白iterate是如何執行查詢的?

首先發出一條查詢對象ID的語句,而後根據對象的ID到緩存(緩存的概念上篇博客已經提到)中查找,如果存在查詢出此對象的其餘的屬性,不然會發出N條語句,此時的N語句,是剛纔第一次查詢的記錄條數。這種現象就是N+1sql語句。

其中list是默認狀況下都發出sql語句,查詢出的結果會放到緩存中,可是它不會利用緩存,即便放進去,下次執行時,仍然繼續發出sql語句。

而:iterate默認狀況下會利用緩存,如果緩存中有則不會發出N+1條語句。

3.條件查詢。

這種方式就是傳入參數,使用參數佔位符「?」。也可使用「:參數名」

Java代碼以下:

[java]  view plain  copy
 
 print?
  1. List students = session.createQuery("select s.id, s.name from Student s where s.name like ?")  
  2.   
  3. .setParameter(0, "%0%")  
  4.   
  5. .list();  
  6.   
  7. List students = session.createQuery("select s.id, s.name from Student s where s.name like :myname")  
  8.   
  9. .setParameter("myname",  "%0%")  
  10.   
  11. .list();  


 4.使用原生sql語句。

     和我們原先寫入的sql語句同樣。在此不介紹了。

 5.外置命名查詢。

      這個聽起來有點晦澀,怎麼理解呢?其實通俗的說就是把hql語句寫在外面,寫在映射文件中。使用標籤:

   

[html]  view plain  copy
 
 print?
  1. <query name="queryStudent">  
  2.   
  3. <![CDATA[ 
  4.  
  5. select s from Student s where s.id <? 
  6.  
  7. ]]>  
  8.   
  9. </query>  


 

    那在程序中是如何使用此標籤的呢?使用session.getNameQuery(),並進行賦值,代碼以下:

[java]  view plain  copy
 
 print?
  1. List students = session.getNamedQuery("queryStudent")  
  2.   
  3. .setParameter(0, 10)  
  4.   
  5. .list();  

 

 6.查詢過濾器。

    這個是什麼意思呢?過濾器你們很熟悉吧,不熟悉的能夠參考個人之前博客<>.原來咱們接觸過編碼過濾器,編碼過濾器就是爲了不當時每一個頁面須要設置編碼格式而提出的。這個查詢過濾器其實也是這個意思。如果代碼都須要某一句sql語句的話,能夠考慮使用它。這樣能夠避免每次都寫查詢語句。

    使用以下:首先在映射文件中配置標籤:

[html]  view plain  copy
 
 print?
  1. <filter-def name="testFilter">  
  2.   
  3. <filter-param type="integer" name="myid"/>  
  4.   
  5. </filter-def>  

 

  而後程序中以下使用並進行賦值:

[java]  view plain  copy
 
 print?
  1. session.enableFilter("testFilter")  
  2.   
  3. .setParameter("myid", 10);  


7.分頁查詢。

    分頁查詢,這個確定不陌生,由於在作drp項目時,作的最多的是分頁,當時使用Oracle數據庫,分頁查詢涉及到三層嵌套。直接傳入的參數爲:每頁的大小(記錄數),頁號。

     Hibernate中給咱們已經封裝好了,只要設置開始的頁號以及每頁的大小便可,不用親自動手寫嵌套的sql語句。

     代碼以下:

[java]  view plain  copy
 
 print?
  1. List students = session.createQuery("from Student")  
  2.   
  3. .setFirstResult(1)  
  4.   
  5. .setMaxResults(2)  
  6.   
  7. .list();  

 

8.對象導航查詢。

這個什麼意思呢?這個只要是用於一個類的屬性是另外一個類的引用。好比:student類中有一個classes屬性。其中的classes也是一個類Class的引用。

當咱們查詢的時候能夠這樣使用:

[java]  view plain  copy
 
 print?
  1. List students = session.createQuery("from Student s where s.classes.name like '%t%'")  
  2.   
  3. .list();  


至關於:s.getClasses.getName(),直接使用get後面的屬性,而後首字母小寫。

 這種語法,是否是很熟悉?想一想咱們在哪是否是也用過?想起來了嗎?估計你猜出來啦,呵呵,是JSTL(jsp standard tag library)中。如果想進一步瞭解,能夠參考個人博客哈,當時是轉載滴貌似。

9.鏈接查詢。

    鏈接分爲:內鏈接和外鏈接,其中外鏈接分爲左鏈接,右鏈接,徹底鏈接。這個跟數據庫中的左右鏈接實際上是同樣的。咱們通俗解釋一下:

    左鏈接:以左邊爲準,右邊即便沒喲匹配的,也要把這條記錄查詢出來,此時沒有匹配的右邊以null填充。

    右鏈接:以右邊爲準,左邊即便沒有匹配的,也要把這條記錄查詢出來,此時沒有匹配的左邊以null填充。

   徹底鏈接:只要一方存在便可。

   內鏈接:必須兩方都存在才能夠查詢提取此記錄。

10.統計查詢。

     其實就是查詢count的記錄數。其中查詢出來的額count是long類型。

11.DML風格的操做。

     DML?其實DML=Data Manipulate Language(數據操做語言),舉個例子:

  

[java]  view plain  copy
 
 print?
  1. session.createQuery("update Student s set s.name=? where s.id<?")  
  2.   
  3. .setParameter(0, "王斌")  
  4.   
  5. .setParameter(1, 2)  
  6.   
  7. .executeUpdate();   

           

倘若原來的名字是:李四,更新完數據庫後變成王斌,如果咱們此時取出數據,其姓名是李四仍是王斌?按照道理應該是王斌,可是結果確實李四,若不信,能夠本身去實踐一下。

這個緣由,是由於更新了數據庫,可是緩存中沒有更新,纔會形成這種數據庫和緩存不一樣步的問題。

因此,咱們應該儘可能不使用這種形式。揚其長避其短嘛。

相關文章
相關標籤/搜索