Hibernate學習筆記

持久層概述
Hibernate基礎
Hibernate映射
Hibernate數據檢索
Hibernate高級特性
Hibernate最佳實踐
Hibernate資源

Hibernate概述
Hibernate核心接口
Hibernate基礎配置

這幾個核心接口幾乎在任何實際開發中都會用到。通過這些接口,不僅可以存儲和獲得持久對象,並且能夠進行事務控制。
Configuration接口
SessionFactory接口
Session接口
Transaction接口
Query和Criteria接口

Configuration 接口負責管理Hibernate 的配置信息。它包括如下內容:Hibernate運行的底層信息:數據庫的URL、用戶名、密碼、JDBC驅動類,數據庫Dialect,數據庫連接池等。Hibernate映射文件(*.hbm.xml)。

Hibernate配置的兩種方法:
屬性文件(Hibernate.properties)。
調用代碼:Configuration config = new Configuration();
Xml文件(Hibernate.cfg.xml)。
調用代碼:Configuration config = new Configuration().configure();

數據庫連接的配置
Hibernate.dialect  net.sf.Hibernate.dialect.MySQLDialect
Hibernate.connection.driver_class  com.mysql.jdbc.Driver
Hibernate.connection.url  jdbc:mysql://localhost/Hibernate
Hibernate.connection.username  root
Hibernate.connection.password  111111
數據庫連接池的配置
Hibernate.connection.provider_class net.sf.Hibernate.connection.DBCPConnectionProvider
其它
Hibernate.show_sql true
Hibernate.jdbc.fetch_size 50
Hibernate.jdbc.batch_size 25

SessionFactory接口
應用程序從SessionFactory(會話工廠)裏獲得Session(會話)實例。它在多個應用線程間進行共享。通常情況下,整個應用只有唯一的一個會話工廠——例如在應用初始化時被創建。然而,如果你使用Hibernate訪問多個數據庫,你需要對每一個數據庫使用一個會話工廠。會話工廠緩存了生成的SQL語句和Hibernate在運行時使用的映射元數據。

創建SessionFactory
Configuration config=new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();

Session接口
Session作爲貫穿Hibernate的持久化管理器核心,提供了衆多持久化方法,如:save,update,delete等。提供了透明地完成了對象的增刪查改操作(CRUD)。
Session不是線程安全的,它代表與數據庫之間的一次操作。
Session通過SessionFactory打開,在所有的工作完成後,需要關閉。

Session創建
Configuration config=new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
創建以後可以調用Session所提供的save、get、delete等方法進行持久化操作。

save
User user=new User();
user.setName(“John”);
session.save(user);
get
User user=(User)session.get(User.class,new Integer(1));

delete
User user=(User)session.get(User.class,new Integer(1));
sesson.delete(user);

Query查詢
Query query=session.createQuery(“from User user where user.name like ?”);
query.setParameter(0,”John”);
List list=query.List();

Criteria查詢
Criteria criteria=session.createCriteria(User.class”);
criteria.add(Restrictions.eq(“name”,”John”));
List list=criteria.List();

Transaction接口
它將應用代碼從底層的事務實現中抽象出來——這可能是一個JDBC事務,一個JTA用戶事務。這有助於保持Hibernate應用在不同類型的執行環境或容器中的可移植性
調用代碼:
    Transaction tx = session.beginTransaction();
     … …
    tx.commit();
注:使用Hibernate進行操作時(增、刪、改)必須顯示的調用Transaction(默認:autoCommit=false)。

Query和Criteria接口
Query接口讓你方便地對數據庫及持久對象進行查詢,它可以有兩種表達方式:HQL語言或本地數據庫的SQL語句。Query經常被用來綁定查詢參數、限制查詢記錄數量,並最終執行查詢操作。

Criteria接口與Query接口非常類似,它允許你創建並執行面向對象的標準化查詢。
值得注意的是Query接口也是輕量級的,它不能在Session之外使用調用代碼:

Query接口
     Query query=session.createQuery(“from User”);
     List users=query.list();
Criteria接口
    Criteria criteria=session.createCriteria(User.class);
     criteria.add(Restrictions.eq(“name”,”John”));
     criteria.add(Restrictions.eq(“sex”,new Integer(1));
     List users=criteria.list();
應用示例
持久化類-User.java
public class User {
     private Long id;
     private String name;
     private Date birthday;
     private String email;
     public User(){
     }
     public User(String name,Date birthday,String email){
          … //Getter/Setter
}

映射文件-User.hbm.xml
<Hibernate-mapping>
<class name="com.test.um.User" table="TBL_USER">
   <id name="id" column="ID">
       <generator class="native"/>
   </id>
   <property name="name" column="NAME"/>
   <property name="birthday" column="BIRTHDAY"/>
   <property name="email" column="EMAIL"/>
</class>
</Hibernate-mapping>

應用-UserTest.java

public void testCreate() throws Exception{
        Configuration cfg = new Configuration();
        cfg.addURL(UserTest.class.getResource("/com/test/um/User.hbm.xml"));
        SessionFactory sessionFactory = cfg.buildSessionFactory();
       
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
       
        SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
        User user = new User("Jack",format.parse("1980-04-12"),"[email protected]");
       
        session.save(user);
        tx.commit();
       
        assertNotNull(user.getId());
        session.clear();
        User user_2 = (User)session.get(User.class,user.getId());
        assertNotNull(user_2);
       
        session.close();
    }
保存用戶:session.save(user);
修改用戶:session.update(user);
保存或修改用戶:session.saveOrUpdate(user);
刪除用戶:session.delete(user);
刪除所有用戶:session.delete(“from User ”);

查詢用戶名爲“test”的用戶:
Query query = session.createQuery("from User where user.name = :name");
query.setParameter(“name",user.getName());
User findUser = (User) query.list().get(0);

基礎配置
Hibernate的配置文件可以有兩種格式:hibernate.properties與hibernate.cfg.xml。配置項大部分都預設了默認值,使用時只需根據實際情況對所需屬性進行配置即可。
dialect 數據庫適配器,用於對特定數據庫提供支持。
connection.driver_class  數據庫JDBC驅動類
connection.url  數據庫URL
connection. username  數據庫訪問用戶名
connection. password  數據庫訪問密碼
connection.datasource JIDI數據源。與2+3配置薦二選一
transactoin.factory_class  指定Transaction實例工廠類
jdbc.fetch_size  JDBC獲取的記錄條數
jdbc.batch_size  每次批量提交閾值
show_sql  是否把執行的SQL語句輸出到控制檯


Hibernate基本數據類型
映射基礎
關聯關係映射
繼承映射

Hibernate提供了豐富的數據類型支持,其中包括了傳統的Java數據類型,如String、Integer,以及JDBC數據類型,如Clob,Blob等。
映射基礎
實體映射技術作爲類與表之間的聯繫紐帶,在ORM實現中起着至關重要的作用。對於Hibernate用戶而言,映射關係更多地體現在配置文件的維護過程中。Hibernate選用XML作爲映射配置文件的基礎形式。

實體映射的核心內容,即實體類與數據庫表之間的映射定義。Hibernate中,類表映射主要包括:
類/表映射
主鍵id映射
屬性/字段映射
複合主鍵映射

類/表映射
<class
        name="ClassName"                                   
        table="tableName"                                   
        dynamic-update="true|false"                     
        dynamic-insert="true|false"                     
/>
(1) name (可選): 持久化類(或者接口)的Java全限定名。 如果這個屬性不存在,Hibernate將假定這是一個非POJO的實體映射。
(2) table (可選 - 默認是類的非全限定名): 對應的數據庫表名。
(3) dynamic-update (可選, 默認爲 false): 指定用於UPDATE 的SQL將會在運行時動態生成,並且只更新那些改變過的字段。
(4) dynamic-insert (可選, 默認爲 false): 指定用於INSERT的 SQL 將會在運行時動態生成,並且只包含那些非空值字段。
主鍵-id映射
<id
        name="propertyName"                                  
        type="typename"                                         
        column="column_name"                           
        unsaved-value="any|none|null|id_value“>  
         <generator class="generatorClass"/>    
</id>


<id
        name="propertyName"                                
        type="typename"                                         
        column="column_name"                          
        unsaved-value="any|none|null|id_value“>   
         <generator class="generatorClass"/>    
</id>
(1)、name (可選) :標識屬性的名稱。
(2)、type(可選):標識Hibernate類型的名字。
(3)、column(可選-默認爲屬性名):對應數據庫表的主鍵字段的名字。
(4)、unsaved-value(可選-默認爲null):這個值用來判斷對象是否要保存。
(5)、主鍵生成方式。

主鍵生成方式:
assigned
主鍵由應用邏輯產生,數據交由Hibernate保存時,主鍵值已經設置完成,無需Hibernate干預。
increment
主鍵按數值順序遞增。
identity
採用數據庫提供的主鍵生成機制,如SQL Server,MySQL中的自增長主鍵生成機制
sequence
採用數據庫提供的sequence機制生成主鍵,如Oracle Sequence
native
由Hibernate根據數據庫適配器中的定義,自動採用identity、hilo、sequence的其中一種作爲主鍵生成方式

屬性/字段映射
<property
        name="propertyName"                            
        column="column_name"                          
        type="typename"                                      
        update="true|false"                               
        insert="true|false"                                  
        formula=“arbitrary SQL expression”  
/>
(1) Name:指定了映射類中的屬性名爲” propertyName”,此屬性將被映射到指定的庫表字段。
(2) column(可選):指定了庫表中對應映射類屬性的字段名。
(3) type(可選):指定了映射字段的數據類型
(4) update, insert (可選 - 默認爲 true) :表明在用於UPDATE 和/或 INSERT的SQL語句中是否包含這個字段。
(5) formula (可選): 一個SQL表達式,定義了這個計算(computed) 屬性的值。計算屬性沒有和它對應的數據庫字段。

複合主鍵映射
Hibernate中,通過composite-id節點對複合主鍵進行定義。
定義方式有兩種:
基於實體類屬性的複合主鍵
基於主鍵類的複合主鍵

基於實體類屬性的複合主鍵
<hibernate-mapping>
<class name=“com.sino.model.User” table=“t_user”>
<composite-id>
 <key-property name=“lastname” column=“lastname” type=“string” />
 <key-property name=“firstname” column=“firstname” type=“string” />
</composite-id>
<property name=“age” column=“age” type=“Integer” />
</class>
</hibernate-mapping>

User實體類:
Public class User implements Serializable{
 private String firstname;
 private String lastName;
 private Integer age;
      … //getter and setter
      public boolean equals(Object object){…}
 public int hashCode(){…}
}

查找方法:
User user=new User();
user.setFirstname(“小小”);
user.setLastname(“張”);
user=(User)session.load(User.class,user);
System.out.println(“User age is=>”+user.getAge());

基於主鍵類的複合主鍵
<hibernate-mapping>
<class name=“com.sino.model.User” table=“t_user”>
<composite-id name=“userpk” class=UserPK>
 <key-property name=“lastname” column=“lastname” type=“string” />
 <key-property name=“firstname” column=“firstname” type=“string” />
</composite-id>
<property name=“age” column=“age” type=“Integer” />
</class>
</hibernate-mapping>

UserPK主鍵類:
Public class UserPK implements Serializable{
 private String firstname;
 private String lastName;
 … //getter and setter
 … //equals and hashCode
}

User實體類:
Public class User implements Serializable{
 private Integer age;
 private UserPK userpk;
 … //getter and setter
}

查找方法:
UserPK userpk=new UserPK();
userpk.setFirstname(“小小”);
userpk.setLastname(“張”);
User user=(User)session.load(User.class,userpk);
System.out.println(“User age is=>”+user.getAge());

關聯關係映射
一對一關聯
一對多關聯
多對多關聯

一對一關聯包括兩種形式:
主鍵關聯
惟一外鍵關聯

主鍵關聯

一對一主鍵關聯形式即兩張關聯表通過主鍵形式一對一映射關係。Hibernate中,通過one-to-one節點對一對一關係進行定義。典型實例:中國公民只允許擁有一份護照.
User.hbm.xml
<hibernate-mapping>
<class name=“com.sino.model.User” table=“t_user”>
<id name=“id” column=“id” type=“java.lang.Integer” />
<property name=“name” column=“name” type=“java.lang.String” />
<property name=“age” column=“age” type=“java.lang.Integer” />
<one-to-one name=“passport”                    
 class=“com.sino.model.Passport”
 cascade=“all”
 outer-join=“true” />
</class>
</hibernate-mapping>

Passport.hbm.xml
<hibernate-mapping>
<class name=“com.sino.model.Passport” table=“t_passport”>
<id name=“id” column=“id”>
 <generator class=“foreign”>
  <param name=“property”>user</param>
 </generator>
</id>
<one-to-one name=“user”                    
 class=“com.sino.model.User”
 constrained=“true” />
<property name=“serial” column=“serial” type=“java.lang.String” />
<property name=“expiry” column=“expiry” type=“java.lang.Integer” />
</class>
</hibernate-mapping>

對關聯對象的保存:
User user=new User();
user.setAge(new Integer(20));
user.setName(“張小小”);

Passport passport=new Passport ();
passport.setSerial(“PDR1234567”);
passport.setExpiry(new Integer(20080101);

//相互設置關聯
passport.setUser(user);
user.setPassport(passport);

Transaction tx=session.beginTransaction();
session.save(user)
tx.commit();

唯一外鍵關聯
唯一外鍵關聯的一對一關係只是多對一關係的一個特例。
假定在一個特定的用戶管理系統中,每個用戶(User)都從屬於一個用戶組
Hibernate節點定義如下
<hibernate-mapping>
<class name=“com.sino.model.User” table=“t_user”>
<id name=“id” column=“id” type=“java.lang.Integer”>
 <generator class=“native” />
</id>
<property name=“name” column=“name” type=“java.lang.String” />
<property name=“age” column=“age” type=“java.lang.Integer” />
<many-to-one name=“group”                    
 class=“com.sino.model.Group”
 column=“group_id”
 unique=“true” />
</class>
</hibernate-mapping>
運行測試代碼
User user=(User)session.load(User.class,new Integer(1));
System.out.println(“Group name=>”+user.getGroup().getName());

屏幕輸出:
Hibernate: select t_user.id as id1_,… left outer join t_group on t_user.group_id=t_group.group_id where t_user.id=?
Group name=>My Group
一對多關聯
一對多關聯包括兩種形式:
單向一對多關聯
雙向一對多關聯
單向一對多關聯只需在”-”方進行配置,雙向一對多需要關聯雙方均加以配置。

單向一對多關聯
User.hbm.xml
<hibernate-mapping>
<class name=“com.sino.model.User” table=“t_user”
 dynamic-update=“true” dynamic-insert=“true”>
<id name=“id” column=“id” type=“java.lang.Integer” />
<property name=“name” column=“name” type=“java.lang.String” />
<property name=“age” column=“age” type=“java.lang.Integer” />
<set name=“addresses”                    
 table=“t_address”
 cascade=“all”
 order_by=“zipcode asc”>
 <key column=“user_id”></key>
 <one-to-many class=“com.sino.model.Address” />
<set>
</class>
</hibernate-mapping>

爲已有用戶增加地址對象
Transaction tx=session.beginTransaction();

Address addr=new Address();
addr.setTel(“86028888”);
addr.sestZipcode(“517099”);
addr.setAddress(“ShenZhen”);

user.getAddresses().add(addr);

session.save(user);

tx.commit();
雙向一對多關聯
雙向一對多關聯,實際上是”一對多”和”多對一”關聯的組合。必須在主控方配置單向”一對多”關係的基礎上,在被控方配置與其對應的”多對一”關係
User.hbm.xml
<hibernate-mapping>
<class name=“com.sino.model.User” table=“t_user”
 dynamic-update=“true” dynamic-insert=“true”>
<id name=“id” column=“id” type=“java.lang.Integer” />
<property name=“name” column=“name” type=“java.lang.String” />
<property name=“age” column=“age” type=“java.lang.Integer” />
<set name=“addresses” table=“t_address”
 lazy=“true”
 inverse=“true”
 cascade=“all”
 sort=“unsorted”
 order_by=“zipcode asc”>
 <key column=“user_id”></key>
 <one-to-many class=“com.sino.model.Address” />
<set>
</class>
</hibernate-mapping>

Address.hbm.xml
<hibernate-mapping>
<class name=“com.sino.model.Address” table=“t_address”
 dynamic-update=“false” dynamic-insert=“false”>
<id name=“id” column=“id” type=“java.lang.Integer” />
<property name=“tel” column=“tel” type=“java.lang.String” />

<many-to-one name=“user” class=“com.sino.model.User”
 cascade=“all”
 outer-join=“auto”
 update=“true”
 insert=“true”
 access=“property”
 column=“user_id”
 not-null=“true”
/>
</class>
</hibernate-mapping>

維護關係

Transaction tx=session.beginTransaction();

Address addr=new Address();
addr.setTel(“86028888”);
addr.sestZipcode(“517099”);
addr.setAddress(“ShenZhen”);

addr.setUser(user);
user.getAddresses().add(addr);

session.save(user);

tx.commit();

多對多關聯
由於引入了中間表,一次讀取操作需要反覆數次查詢,多對多關聯的性能不佳,設計時應該儘量避免大量使用。
在一個權限管理系統中,一個常見的多對多的映射關係是Role與Privilege之間的映射:
Role代表”角色”(如:會計、出納)
Privilege代表某個特定資源的訪問特權(如修改財務報表,查詢財務報表)一個Role可以有多種Privilege,一個Privilege可同時屬於多個Role

Role.hbm.xml
<hibernate-mapping>
<class name=“com.sino.model.Role” table=“t_role”
 dynamic-update=“false” dynamic-insert=“false”>
<id name=“id” column=“id” type=“java.lang.Integer” />
<property name=“name” column=“name” type=“java.lang.String” />

<set name=“privileges” table=“t_role_ privilege”
 lazy=“true”
 inverse=“false”
 cascade=“save-update”>
 <key column=“role_id”></key>
 <many-to-many class=“com.sino.model.Privilege” column=“privilege_id”/>
<set>
</class>
</hibernate-mapping>

Privilege.hbm.xml
<hibernate-mapping>
<class name=“com.sino.model.Privilege” table=“t_privilege”
 dynamic-update=“false” dynamic-insert=“false”>
<id name=“id” column=“id” type=“java.lang.Integer” />
<property name=“name” column=“name” type=“java.lang.String” />

<set name=“roles” table=“t_role_ privilege”
 lazy=“true”
 inverse=“true”
 cascade=“save-update”>
 <key column=“privilege_id”></key>
 <many-to-many class=“com.sino.model.Role” column=“role_id” outer-join=“auto”/>
<set>
</class>
</hibernate-mapping>

保存關係代碼:
Role role1=new Role();
role1.setName(“Role1”);

Role role2=new Role();
role2.setName(“Role2”);

Privilege privilege1=new Privilege();
privilege1.setName(“Privilege1”);

Privilege privilege2=new Privilege();
privilege2.setName(“Privilege2”);

Privilege1.getRoles().add(role1);
Privilege1.getRoles().add(role2);

Privilege2.getRoles().add(role1);

role1.getPrivileges.add(privilege1);
role1.getPrivileges.add(privilege2);

role2.getPrivileges.add(privilege1);
Try{
 Transaction tx = session.beginTransaction();
 //多對多關係必須同時對關聯雙方進行保存
 session.save(role1);
 session.save(role2);

 session.save(privilege1);
 session.save(privilege2);

 tx.commit();
}catch(Exception e)
 …
}

繼承映射
繼承關係是關係型數據與面向對象數據結構之間的主要差異之一。
Hibernate支持三種類型的繼承關係
每個具體類一張表(Table per concrete class)
表與子類之間的獨立一對一關係
每個子類一張表(Table per subclass)
每個子類對應一張子表,並與主類共享主表
每個類分層結構一張表(Table per class hierarchy)
表與類的一對多關係

每個具體類一張表
Book.hbm.xml
<class name=“example.model.Book” table=“t_book”>
<id name=“id” column=“id” type=“java.lang.Integer”>
 <generator class=“native” />
</id>
<property name=“manufacturer” column=“manufacturer” … />

<property name=“pageCount” column=“page_count” … />
</class>

DVD.hbm.xml
<class name=“example.model.DVD” table=“t_dvd”>
<id name=“id” column=“id” type=“java.lang.Integer”>
 <generator class=“native” />
</id>
<property name=“manufacturer” column=“manufacturer” … />

<property name=“regionCode” column=“region_code” … />
</class>

查詢Product
Query query=session.createQuery(“from example.model.Product”);
List products=query.list();

每個子類一張表
Product.hbm.xml
<class name=“example.model.Product” table=“t_product”>
<id name=“id” column=“id” type=“java.lang.Integer”>
 <generator class=“native” />
</id>
<property name=“manufacturer” column=“manufacturer” … />
<property name=“name” column=“name” … />
<joined-subclass name=“example.model.Book” table=“t_book”>
 <key column=“id” />
 <property name=“pageCount” column=“page_count” />
</joined-subclass>
<joined-subclass name=“example.model.DVD” table=“t_dvd”>
 <key column=“id” />
 <property name=“regionCode” column=“region_code” />
</joined-subclass>
</class>

查詢Product
Query query =session.createQuery(“from example.model.Product”);
List products=query.list();

每個類分層結構一張表
t_product表不但包括Product的id,name,manufacturter字段,同時還包含了Book的page_count字段、DVD的region_code字段,不同的類型商品通過(category)字段加以區分。

Product.hbm.xml
<class name=“example.model.Product” table=“t_product”>
<id name=“id” column=“id” type=“java.lang.Integer”>
 <generator class=“native” />
</id>
<discriminator column=“category” type=“string” />
<property name=“manufacturer” column=“manufacturer” … />
<property name=“name” column=“name” … />
<subclass name=“example.model.Book” discriminator-value=“book”>
 <property name=“pageCount” column=“page_count” />
</subclass>
<subclass name=“example.model.DVD” discriminator-value =“dvd”>
 <property name=“regionCode” column=“region_code” />
</subclass>
</class>

查詢Book
Query query =session.createQuery(“from example.model.Book”);
List books=query.list();
Hibernate會根據配置自動進行類型識別,把t_product表中category=book的數據(Book) 全部查詢出來。
每個具體類一張表
每個子類一張表
每個類分層結構一張表

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章