hibernate學習筆記

hibernate中load和get方法的區別

 1)當數據庫不存在對應ID數據時,調用load()方法將會拋出ObjectNotFoundException異常,get()方法將返回null.

2)也就是延時加載的區別。load的方法默認要加載的對象是存在數據庫中的,返回的是一個代理對象而不是一個真正的類實例,

當用到具體與數據庫有關的數據時候才查詢數據庫,而get方法直接查詢數據庫,返回類的實例。

3)get方法首先查詢session緩存,沒有的話查詢二級緩存,最後查詢數據庫;反而load方法創建時首先查詢session緩存,沒有

就創建代理,實際使用數據時才查詢二級緩存和數據庫。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Hibernate的工作流程:

1. 讀取並解析配置文件

2. 讀取並解析映射信息,創建SessionFactory

3. 打開Sesssion

4. 創建事務Transation

5. 持久化操作

6. 提交事務

7. 關閉Session

8. 關閉SesstionFactory

Hibernate中bean 的三種狀態

Hibernate對象分爲三種狀態:瞬時態(new 出來的或者實例化時session無關的),持久態(session關聯)與託管態(曾經與session關聯)。

其中持久態的對象是PO,瞬時態、託管態的對象可作爲VO。(PO不應該直接用作v層)所以在使用中應該注意三態的轉化。

如:在進行數據操作的一系列過程中,save或者saveorupdate操作可以把順勢態或者託管態的對象轉換成持久態,而delete或者session的close、

flush等操作將會把session相關聯的持久態對象轉換成託管態。

 

hibernate的映射有2種方式
xml和 annotaion 

xml的好處是:它是配置!是脫離代碼之外的東西,可以允許你在你的項目部署之後,再去做細微修改(如果你的項目做得有彈性的話)
xml的缺點:繁瑣!寫了一大堆,發現節點的字數比真實數據的字數多太多了...浪費!

annotation的好處:維護的頁面少!不用寫項目的時候在N的文檔直接,切來切去的!而且非常簡練,比xml少非常多!
annotation的壞處:和程序糾纏在了一起...

推薦用法:
在項目開發階段用annotation做配置,這樣可以大大提高項目的效率

等到項目開發,測試完成之後,再重新寫回xml然後再去部署
 
 
二級緩存配置: 1、首先要打開二級緩存,在hibernate.cfg.xml中添加如下配置: <property   name= "hibernate.cache.use_second_level_cache "> true </property> 2、Hibernate的二級緩存使用第三方的緩存工具來實現,所以我們需要指定Hibernate使用哪個      緩存工具。如下配置指定Hibernate使用EhCache緩存工具。 <property   name= "hibernate.cache.provider_class "> org.hibernate.cache.EhCacheProvider </property> 3、Hibernate在默認情況下並不會對所有實體對象進行緩存,所以,我們需要指定緩存哪些對象, 在實體對象的映射文件中(相應的 <class> 標籤內部),添加如下配置: <cache   usage= "read-only "/> usage= "read-only "是“只讀”緩存策略。 注意,這個 <cache> 標籤只能放在 <class> 標籤的內部,而且必須處在 <id> 標籤的前面!!! 這個 <cache> 標籤放在哪些 <class> 標籤下面,就說明會多這些類的對象進行緩存 4、對於第3步,有一個可選的方案是在hibernate.cfg.xml文件中指定哪些類的對象需要緩存,      而不需要使用 <cache> 標籤來指定。如:      在hibernate.cfg.xml中添加如下配置:      <class-cache   class= "com.bjsxt.hibernate.Classes "   usage= "read-only "   />            注意,這個 <class-cache> 標籤必須放在 <mapping> 標籤的後面!!

Hibernate配置文件詳解

 Hibernate的基本配置文件有兩種:hibernate.cfg.xml.hbm.xml文件。前者包含了Hibernate與數據庫的基本連接信息,在Hibernate工作的初始階段,這些信息被先後加載到ConfigurationSessionFactory實例;後者包含了Hibernate的基本映射信息,即系統中每一個類與其對應的數據庫表之間的關聯信息,在Hibernate工作的初始階段,這些信息通過hibernate.cfg.xmlmapping節點被加載到ConfigurationSessionFactory實例。這兩種文件信息包含了Hibernate的所有運行期參數。下面我們用詳細的例子來說明這兩種文件的基本結構和內容。
一、hibernate.cfg.xml文件:
     <!--該文件的開頭信息,對Hibernate而言,該類文件基本都這麼開頭:)-->
     <?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節點就夠了,除非我們中間使用了多個數據庫-->
     <session-factory>
     <!--用戶名 -->
     <property name="connection.username">root</property>
     <!--url信息 --> 
     <property name="connection.url">jdbc:mysql://localhost:3306/webases</property>
     <!--數據庫方言信息--> 
     <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
     <!--密碼 --> 
     <property name="connection.password">274507</property>
     <!--數據庫驅動信息 --> 
     <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
     <!--指定Hibernate映射文件路徑 -->
     <mapping resource="com/Hibernate/test_products.hbm.xml" />
     </session-factory>
     </hibernate-configuration>
二、.hbm.xml文件:
     由於Hibernate的關聯關係包含了一對一、一對多、多對一和多對多等四種類型,因此,也就有分別與之對應的四種.hbm.xml文件。下面我們就以比較常用的雙向一對多型關聯關係爲例,介紹一下.hbm.xml文件的基本結構和內容。有關Hibernate更詳細的內容,請參考相關文資料。
     該例中有兩張數據庫表:一張爲表,另一張爲表,所用的數據庫爲MySQL。二者的建表語句如下:
     CREATE TABLE IF NOT EXISTS Province
     ( 
        Guid                      INT               NOT NULL AUTO_INCREMENT, 
        Provincename         VARCHAR(16)  NOT NULL, 
        PRIMARY KEY (Guid)
     )  TYPE=InnoDB; 
     CREATE TABLE IF NOT EXISTS City
     ( 
        Guid                      INT               NOT NULL AUTO_INCREMENT, 
        Cityname               VARCHAR(32)  NOT NULL, 
        ProvinceID              INT              NOT NULL, 
        PRIMARY KEY (Guid)
     )  TYPE=InnoDB;
     ALTER TABLE City ADD CONSTRAINT CityRFProvince FOREIGN KEY (ProvinceID)
     REFERENCES Province (Guid) ON DELETE CASCADE ON UPDATE RESTRICT;
     Province表爲主控方,City表爲被控方,兩者之間存在雙向的一對多的關係。表City通過外鍵ProvinceID與表Province進行關聯:當表Province中有記錄被刪除時,表City中相關記錄亦被刪除;當表Province中有記錄被保存或者更新時,表City中相關記錄無任何變化。
     Hibernate自帶工具Middlegen生成的Province.hbm.xml文件進行修改,內容如下:
     <!--該文件的開頭信息,對Hibernate而言,該類文件基本都這麼開頭:)-->
     <?xml version="1.0"?> 
     <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 
        "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd
     >  
     <!-- 映射文件開始 -->    
     <hibernate-mapping> 
     <!-- 下面的class節點定義了Province類和對應數據庫表之間的關聯關係 --> 
     <class 
        name="com.xxx.hibernate.Province" 
        table="Province" 
     >  
     <!-- 下面的兩個節點定義了Province類中的屬性和該類對應數據庫表中的字段之間的關聯關係,其中Guid爲對應數據庫表的主鍵 -->
     <id
        name="guid"
        type="int"
        column="Guid"
     >
     <generator class="native" />
     </id>
     <property
        name="provincename"
        type="java.lang.String"
        column="Provincename"
        not-null="true"
        length="16" 
     >   
     </property> 
     <!-- 下面的set節點定義了Province類和City類之間的”一對多“型關聯關係 --> 
     <set
        name="cities"<!-- 集合屬性的名稱 -->
        lazy="true"<!-- 是否允許延遲加載 -->
        inverse="true"<!-- 定義這個集合是否爲雙向關聯關係中的方向一端 -->
        cascade="delete"<!-- 定義有關操作是否關聯到子實體(此處指City類對象) --> 
     > 
     <key> 
        <column name="ProvinceID" /><!-- 定義集合所對應的數據庫表的外鍵 --> 
     </key> 
     <one-to-many 
        class="com.xxx.hibernate.City"<!-- 定義集合所屬的類--> 
     /> 
     </set>  
     </class> 
     </hibernate-mapping> 
     Hibernate自帶工具Middlegen生成的City.hbm.xml文件進行修改,內容如下: 
     <!--該文件的開頭信息,對Hibernate而言,該類文件基本都這麼開頭:)--> 
     <?xml version="1.0"?> 
     <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 2.0//EN" 
        "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd
     >  
     <!-- 映射文件開始 -->   
     <hibernate-mapping> 
     <!-- 下面的class節點定義了City類和對應數據庫表之間的關聯關係 --> 
     <class 
        name="com.xxx.hibernate.City" 
        table="City" 
     >  
     <!-- 下面的兩個節點定義了City類中的屬性和該類對應數據庫表中的字段之間的關聯關係,其中Guid爲對應數據庫表的主鍵--> 
     <id
        name="guid"
        type="int"
        column="Guid" 
     > 
     <generator class="native" /> 
     </id>   
     <property
        name="cityname"
        type="java.lang.String"
        column="Cityname"
        not-null="true"
        length="32" 
     >    
     </property> 
     <!-- 下面的many-to-one節點定義了Province類和City類之間的”一對多“型關聯關係 --> 
     <many-to-one 
        name="province"<!-- 屬性名稱 --> 
        class="com.xxx.hibernate.Province"<!-- 屬性所屬的類 -->
        cascade="none"<!-- 指定哪些操作會從父對象(此處指City類對象)級聯到子對象(此處指Province類對象) -->
        outer-join="auto"<!-- 設置父子對象之間是否存在外連接 -->
        not-null="true"<!-- 指定該屬性是否一定爲非空 --> 
     > 
     <column name="ProvinceID" /><!-- 定義父對象(此處指City類對象)所對應的數據庫表的外鍵 --> 
     </many-to-one> 
     </class>  
     </hibernate-mapping>

 

 

多對多的雙向關聯關係(中間表)

在多對多的關聯關係中,可拆分爲兩個一對多的關聯關係,即在兩個表中間增加一個關聯表,記錄這兩個表之間的關聯關係。若拋開關聯表,則原2個表之間看不出任何的關係。

以爲考試類別和考試科目爲例,詳細講解在添加關聯表的情況下兩個表之間的hibernate設置。
考試類別表:exam_sort_enum
id:integer
name:string
考試科目表:
subject
id:integer
name:string
考試類別科目關聯表

exam_sort_enum_id:integer    對應考試類別表的id
subject_id:integer           對應考試科目表的id


ExamSortEnum.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class
     name="model.ExamSortEnum"
     table="EXAM_SORT_ENUM"
     lazy="false"
>
     <id
         name="id"
         type="integer"
         column="ID"
         length="22"
     >
         <generator class="increment" />
     </id>
    
     <property
         name="name"
         type="string"
         column="NAME"
         length="255"
     />
    <set name="subject" table="EXAM_SORT_ENUM_SUBJECT" lazy="true" cascade="save-update">
      <key column="exam_sort_enum_id"/>
<many-to-many column="subject_id" class="model.Subject"/>
    </set>
</class>
</hibernate-mapping>


ExamSortEnum.java

package model;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

public class ExamSortEnum   implements Serializable{


private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Set subject = new HashSet();

public ExamSortEnum(){}
public ExamSortEnum(Integer id){
   setId(id);
}

public void setSubject(Set subject){
   this.subject = subject;
}

public Set getSubject(){
   return this.subject;
}

public Integer getId() {
   return id;
}

public void setId(Integer id) {
   this.id = id;
}

public String getName() {
   return name;
}

public void setName(String name) {
   this.name = name;
}
}


關於映射文件:

映射文件要設置set,name=subject 爲ExamSortEnum.java文件中定義的Set對象,存儲多個Subject類型的容器。
table="EXAM_SORT_ENUM_SUBJECT" 爲對應的中間表的表名,由於兩個業務表之間不能直接打交道,只能通過中間表來進行關聯。
lazy="true" 延遲加載
cascade="save-update" 級聯保存更新,若設置爲all,delete,all-delete-orphans,則在刪除一個ExamSortEnum對象時,關聯的Subject對象也被刪除,而此關聯的subject對象可能被其他的爲ExamSortEnum對象所引用。
<key column="exam_sort_enum_id"/> 指定中間表中參照爲Exam_Sort_Enum表的外鍵爲exam_sort_enum_id
<many-to-many>
column="subject_id" Exam_Sort_Enum表參照Subject表的外鍵爲subject_id,即Exam_Sort_Enum表通過subject_id與Subject表關聯

class="model.Subject" 指定set中name=subject中存放的是model.Subject對象。


Subject.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class
     name="model.Subject"
     table="SUBJECT"
     lazy="false"
>
     <id
         name="id"
         type="integer"
         column="ID"
         length="22"
     >
         <generator class="increment" />
     </id>
    
     <property
         name="name"
         type="string"
         column="NAME"
         length="200"
     />
   
    <set name="examSortEnum" table="EXAM_SORT_ENUM_SUBJECT" lazy="true" inverse="true" cascade="save-update">
      <key column="subject_id"/>
<many-to-many column="exam_sort_enum_id" class="model.ExamSortEnum"/>
    </set>
</class>
</hibernate-mapping>

Subject.java

package model;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

public class Subject implements Serializable{

private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Set examSortEnum = new HashSet();


public Subject(){}
public Subject(Integer id){
   setId(id);
}
  
public void setExamSortEnum(Set examSortEnum){
   this.examSortEnum = examSortEnum;
}
public Set getExamSortEnum(){
   return this.examSortEnum;
}

public Integer getId() {
   return id;
}

public void setId(Integer id) {
   this.id = id;
}

public String getName() {
   return name;
}

public void setName(String name) {
   this.name = name;
}
}


關於映射文件:
內容與ExamSortEnum.hbm.xml差不多,只是多了一個inverse="true",告訴hibernate控制權不在此處,兩個映射文件只能設置一個。

測試類:
package model;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class ExamSortEnumTest {
public static SessionFactory sf ;

static{
   try{
    Configuration cfg = new Configuration().configure();
    sf = cfg.buildSessionFactory();
   }catch(Exception e){
    e.printStackTrace();
   }
}

public void insert1(){
   Session sess = sf.openSession();
   Transaction tx = sess.beginTransaction();
  
   Subject sa = new Subject();
   sa.setName("A1");
  
   Subject sb = new Subject();
   sb.setName("B1");

   Subject sc = new Subject();
   sc.setName("C1");
  
   ExamSortEnum esea = new ExamSortEnum();
   esea.setName("A");
   esea.getSubject().add(sa);
   esea.getSubject().add(sc);
  
   ExamSortEnum eseb = new ExamSortEnum();
   eseb.setName("B");
   eseb.getSubject().add(sb);
   eseb.getSubject().add(sc);

   sess.save(esea);
   sess.save(eseb);
  
   tx.commit();
   sess.close();
  
}

public static void main(String[] args){
   ExamSortEnumTest et = new ExamSortEnumTest();
   et.insert1();
}
}

 

發佈了83 篇原創文章 · 獲贊 26 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章