Hibernete 配置及 HQL 語法查詢

http://hi.baidu.com/leyoochina/item/04dd868d93f8b98f4414cffb


http://blog.sina.com.cn/s/blog_825bd5620100zalu.html


Hibernate中outer-join、lazy 、fetch join關鍵字的使用:http://hi.baidu.com/xizenyin/item/78e0e0f545a69ecf521c266a

2009-05-22 11:34

Hibernate中outer-join、lazy 、fetch join關鍵字的使用

關鍵字: outer-join lazy fetch join

1、outer-join關鍵字(many-to-one的情況)

outer-join關鍵字有3個值,分別是true,false,auto,默認是auto。
true: 表示使用外連接抓取關聯的內容,這裏的意思是當使用load(OrderLineItem.class,"id")時,Hibernate只生成一條SQL語句將OrderLineItem與他的父親Order全部初始化。

select * from OrderLineItem o left join Order p on o.OrderId=p.OrderId   where o.OrderLineItem_Id=?

false:表示不使用外連接抓取關聯的內容,當load(OrderLineItem.class,"id")時,Hibernate生成兩條SQL語句,一條查詢OrderLineItem表,另一條查詢Order表。這樣的好處是可以設置延遲加載,此處要將Order類設置爲lazy=true。

select * from OrderLineItem o where o.OrderLineItem_Id=?
select * from Order p where p.OrderId=?

auto:具體是ture還是false看hibernate.cfg.xml中的配置

注意:如果使用HQL查詢OrderLineItem,如 from OrderLineItem o where o.id='id',總是不使用外部抓取,及outer-join失效。

2、outer-join(集合)

由於集合可以設置lazy="true",所以lazy與outer-join不能同時爲true,當lazy="true"時,outer-join將一直是false,如果lazy="false",則outer-join用法與1同

3、HQL語句會將POJO配置文件中的關聯一併查詢,即使在HQL語句中沒有明確join

4、In HQL, the "fetch join" clause can be used for per-query specific outer join fetching. One important thing many people miss there, is that HQL queries will ignore the outer-join attribute you specified in your mapping. This makes it possible to configure the default loading behaviour of session.load() and session.get() and of objects loaded by navigating relationship. So if you specify

and then doMyObject obj = session.createQuery("from MyObject").uniqueResult();
obj.getMySet().iterator().next();

you will still have an additional query and no outer-join. So you must explicily request the outer-join fetching:

MyObject obj = session.createQuery(
"from MyObject mo left join fetch mo.mySet").uniqueResult();
obj.getMySet().iterator().next();

Another important thing to know is that you can only fetch one collection reference in a query. That means you can just use one fetch join. You can however fetch "one" references in addition, as this sample from the Hibernate Docs demonstrates:

from eg.Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens

We have once considered lifting this limitation, but then decided against it, because using more than one fetch-join would be a bad idea generally: The generated ResultSet becomes huge and is a major performance loss.

So alltogether the "fetch join" clause is an important instrument Hibernate users should learn how to leverage, as it allows tuning the fetch behaviour of a certain use case.

5、join fetchjoin 的區別

如果HQL使用了連接,但是沒有使用fetch關鍵字,則生成的SQL語句雖然有連接,但是並沒有取連接表的數據,還是需要單獨的sql取數據,也就是 select a,b,d...中沒有連接表的字段

6、如果集合被聲明爲lazy=true,在HQL中如果顯式的使用 join fetch 則延遲加載失效。

7、在one-to-many的one端顯式設置fecth="join",則無論如何都採取預先抓取(生成一個SQl),延遲加載失效(生成兩個SQL)

8、many-to-one的延遲加載是在配置文件的class標籤設置 lazy="true",one-to-many和many-to-many的延遲加載是在set標籤中設置lazy="true"。而one-to- one不只要在calss標籤設置lazy="true",而且要在one-to-one標籤中設置constrained="true".



lazy:與之關係關鍵詞(fetch:只用在left join 與 inner join 中) ex: from a left join fetch a.b as b (on 省略以在hbm.xml配置好),是否(及時加載 延遲加載 預加載)關聯對象數據


在“一”方 <set>......<one-many/></set>   在“多”方<many-one/>


inverse:

一對多時(一個班級有多個學生),一般inverse="true",減少update,由多個員工認識老闆容易;

              多對一(多個學生屬於一個班級),默認值inverse="false"


多對多:

<set name="roleSet" table="t_user" cascade="all" outer-join="false">  不是外鍵關聯


一對一:


  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 package="com.reiyen.hibernate.domain">  
  6.     <class name="IdCard" table="id_card">  
  7.         <id name="id">  
  8.             <!-- id_card的主鍵來源person,也就是共享idCard的主鍵 -->  
  9.             <generator class="foreign">  
  10.                 <param name="property">person</param>  
  11.             </generator>  
  12.         </id>  
  13.         <property name="authorizeDate" column="authorize_date" />  
  14.         <!-- one-to-one標籤的含義,指示hibernate怎麼加載它的關聯對象,默認根據主鍵加載,   
  15.             constrained="true", 表明當前主鍵上存在一個約束,id_card的主鍵作爲外鍵參照了person -->  
  16.         <one-to-one name="person" constrained="true"></one-to-one>  
  17.     </class>  
  18. </hibernate-mapping> 


cascade:設置級聯
  sava-update:級聯保存、更新
  delete:級聯刪除
  none:不級聯,默認值
  all:級聯保存、更新、刪除

主鍵:


1. 主鍵(id)

Hibernate的主鍵生成策略有如下幾種:

1) assigned

主鍵由外部程序負責生成,在 save() 之前指定。

2) hilo

通過hi/lo 算法實現的主鍵生成機制,需要額外的數據庫表或字段提供高位值來源。

3) seqhilo

與hilo 類似,通過hi/lo 算法實現的主鍵生成機制,需要數據庫中的 Sequence,適用於支持 Sequence 的數據庫,如Oracle。

4) increment

主鍵按數值順序遞增。此方式的實現機制爲在當前應用實例中維持一個變量,以保存着當前的最大值,之後每次需要生成主鍵的時候將此值加1作爲主鍵。這種方式可能產生的問題是:不能在集羣下使用。

5) identity

採用數據庫提供的主鍵生成機制。如DB2、SQL Server、MySQL 中的主鍵生成機制。

6) sequence

採用數據庫提供的 sequence 機制生成主鍵。如 Oralce 中的Sequence。

7) native

由 Hibernate 根據使用的數據庫自行判斷採用 identity、hilo、sequence 其中一種作爲主鍵生成方式。

8) uuid.hex

由 Hibernate 基於128 位 UUID 算法 生成16 進制數值(編碼後以長度32 的字符串表示)作爲主鍵。

9) uuid.string

與uuid.hex 類似,只是生成的主鍵未進行編碼(長度16),不能應用在 PostgreSQL 數據庫中。

10) foreign

使用另外一個相關聯的對象的標識符作爲主鍵。

主鍵配置舉例如下:

<id name="id" column="id" type="java.lang.Integer">

<generator class="native"/>

</id>

另外還可以擴展Hibernate的類來做自己的主鍵生成策略,具體例子見:http://www.javaeye.com/topic/93391




fetch定義的是兩個關聯對象的抓取策略,得到一個對象時怎麼去得到另外一個對象,是通過連接查詢(join)還是另外發起一條sql等。一方存在和另外一方存在是不衝突的。

outer-join關鍵字(many-to-one的情況)
outer-join關鍵字有3個值,分別是true,false,auto,默認是auto。
true: 表示使用外連接抓取關聯的內容,這裏的意思是當使用load(OrderLineItem.class,"id")時,Hibernate只生成一條SQL語句將OrderLineItem與他的父親Order全部初始化。
select * from OrderLineItem o left join Order p on o.OrderId=p.OrderId  where o.OrderLineItem_Id=?
false:表示不使用外連接抓取關聯的內容,當load(OrderLineItem.class,"id")時,Hibernate生成兩條 SQL語句,一條查詢OrderLineItem表,另一條查詢Order表。這樣的好處是可以設置延遲加載,此處要將Order類設置爲 lazy=true。
select * from OrderLineItem o where o.OrderLineItem_Id=?
select * from Order p where p.OrderId=?
auto:具體是ture還是false看hibernate.cfg.xml中的配置


多對多(他是基於兩個多對一,其實還有不用配置第三章變的方法)


. 完整實例

Hibernate 多對多雙向關聯配置舉例

一、模型介紹
 
多個人(Person)對應多個地址(Address)。
一個人可對應多個地址,一個地址也可以對應多個人。
 
二、實體(省略getter、setter方法)
 
public class Personnn_sx {
    private int personid;
    private String name;
    private int age;
    private Set addresses=new HashSet();
 
public class Addressnn_sx {
    private int addressid;
    private String addressdetail;
    private Set persons = new HashSet();
 
三、表模型
 
mysql> desc person_nn_sx;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| personid | int(11)      | NO   | PRI | NULL    | auto_increment |
| name     | varchar(255) | YES  |     | NULL    |                |
| age      | int(11)      | YES  |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
 
mysql> desc address_nn_sx;
+---------------+--------------+------+-----+---------+----------------+
| Field         | Type         | Null | Key | Default | Extra          |
+---------------+--------------+------+-----+---------+----------------+
| addressid     | int(11)      | NO   | PRI | NULL    | auto_increment |
| addressdetail | varchar(255) | YES  |     | NULL    |                |
+---------------+--------------+------+-----+---------+----------------+
 
mysql> desc join_nn_sx;
+-----------+---------+------+-----+---------+-------+
| Field     | Type    | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+-------+
| addressid | int(11) | NO   | PRI |         |       |
| personid  | int(11) | NO   | PRI |         |       |
+-----------+---------+------+-----+---------+-------+
 
四、生成的SQL腳本
 
/* Formatted on 2007/08/22 17:59 (QP5 v5.50) */
CREATE TABLE `address_nn_sx` (
  `addressid` int(11) NOT NULL auto_increment,
  `addressdetail` varchar(255) default NULL,
  PRIMARY KEY  (`addressid`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;
 
/* Formatted on 2007/08/22 17:59 (QP5 v5.50) */
CREATE TABLE `person_nn_sx` (
  `personid` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `age` int(11) default NULL,
  PRIMARY KEY  (`personid`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;
 
/* Formatted on 2007/08/22 17:59 (QP5 v5.50) */
CREATE TABLE `join_nn_sx` (
  `addressid` int(11) NOT NULL,
  `personid` int(11) NOT NULL,
  PRIMARY KEY  (`personid`,`addressid`),
  KEY `FK6EBBC5EF6C600921` (`personid`),
  KEY `FK6EBBC5EF2A92FF3D` (`addressid`),
  CONSTRAINT `FK6EBBC5EF2A92FF3D` FOREIGN KEY (`addressid`) REFERENCES `address_nn_sx` (`addressid`),
  CONSTRAINT `FK6EBBC5EF6C600921` FOREIGN KEY (`personid`) REFERENCES `person_nn_sx` (`personid`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;
 
五、映射方法
 
<hibernate-mapping>
    <class name="com.lavasoft.sx._n_n.Personnn_sx" table="PERSON_nn_sx">
        <id name="personid">
            <generator class="identity"/>
        </id>
        <property name="name"/>
        <property name="age"/>
        <!--映射集合屬性,關聯到持久化類-->
        <!--table="join_1ntab_sx"指定了連接表的名字-->
        <set name="addresses"
             table="join_nn_sx"
             cascade="all">
            <!--column="personid"指定連接表中關聯當前實體類的列名-->
            <key column="personid" not-null="true"/>
            <!--column="addressid"是連接表中關聯本實體的外鍵-->
            <many-to-many column="addressid"
                          class="com.lavasoft.sx._n_n.Addressnn_sx"/>
        </set>
    </class>
</hibernate-mapping>
 
<hibernate-mapping>
    <class name="com.lavasoft.sx._n_n.Addressnn_sx"
           table="ADDRESS_nn_sx">
        <id name="addressid">
            <generator class="identity"/>
        </id>
        <property name="addressdetail"/>
        <!--table="join_nn_sx"是雙向多對多的連接表-->
        <set name="persons"
             inverse="true"
             table="join_nn_sx">
            <!--column="addressid"是連接表中關聯本實體的外鍵-->
            <key column="addressid"/>
            <many-to-many column="personid"
                          class="com.lavasoft.sx._n_n.Personnn_sx"/>
        </set>
    </class>
</hibernate-mapping>
 
六、測試方法
 
public class Test_nn_sx {
    public static void main(String[] args){
        Addressnn_sx add1=new Addressnn_sx();
        Addressnn_sx add2=new Addressnn_sx();
        Personnn_sx p1=new Personnn_sx();
        Personnn_sx p2=new Personnn_sx();
 
        add1.setAddressdetail("鄭州市經三路");
        add2.setAddressdetail("合肥市宿州路");
        p1.setName("wang");
        p1.setAge(30);
        p2.setName("zhang");
        p2.setAge(22);
 
        p1.getAddresses().add(add1);
        p1.getAddresses().add(add2);
        p2.getAddresses().add(add2);
        add1.getPersons().add(p1);
        add2.getPersons().add(p1);
        add2.getPersons().add(p2);
 
 
        Session session= HibernateUtil.getCurrentSession();
        Transaction tx=session.beginTransaction();
        session.save(p1);
        session.save(p2);
//        session.saveOrUpdate(add1);
//        session.saveOrUpdate(add2);
        tx.commit();
        HibernateUtil.closeSession();
    }
}
 
七、測試結果
 
1) :正常保存.
        session.save(p1);
        session.save(p2);
//        session.saveOrUpdate(add1);
//        session.saveOrUpdate(add2);
 
  Hibernate: insert into PERSON_nn_sx (name, age) values (?, ?)
  Hibernate: insert into ADDRESS_nn_sx (addressdetail) values (?)
  Hibernate: insert into ADDRESS_nn_sx (addressdetail) values (?)
  Hibernate: insert into PERSON_nn_sx (name, age) values (?, ?)
  Hibernate: insert into join_nn_sx (personid, addressid) values (?, ?)
  Hibernate: insert into join_nn_sx (personid, addressid) values (?, ?)
  Hibernate: insert into join_nn_sx (personid, addressid) values (?, ?)



在本小節中舉一些.hbm.xml映射文件的例子,讓開發人員對其有一個感性的認識。接下來講述一個用戶表(tbl_user)、用戶與角色關聯表(tbl_user_role)、角色表(tbl_role)以及組織表(tbl_organization)的例子。

(1)tbl_user

<?xml version="1.0" encoding='UTF-8'?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="com.amigo.dao.pojo">

<class name="User" table="tbl_user">

<id name="loginname" column="loginName" type="java.lang.String">

<generator class="assigned"/>

</id>

<property name="name" column="name" type="java.lang.String" not-null="true" />

<property name="password" column="password" type="java.lang.String" not-null="true" />

<property name="mobile" column="mobile" type="java.lang.String" />

<property name="telephone" column="telephone" type="java.lang.String" />

<property name="email" column="email" type="java.lang.String" />

<property name="createtime" column="createTime" type="java.util.Date" not-null="true" />

<property name="lastlogintime" column="lastLoginTime" type="java.util.Date" />

<property name="logintimes" column="loginTimes" type="java.lang.Long" not-null="true" />

<property name="state" column="state" type="java.lang.Byte" not-null="true" />

<property name="description" column="description" type="java.lang.String" />

<many-to-one name="organization" column="orgId" class="Organization" not-null="true" />

<set name="userRoleSet" inverse="true" cascade="all-delete-orphan" lazy="true">

<key column="loginName"/>

<one-to-many class="UserRole"/>

</set>

</hibernate-mapping>

(2)tbl_organization

<?xml version="1.0" encoding='UTF-8'?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="com.amigo.dao.pojo">

<class name="Organization" table="tbl_organization">

<id name="orgid" column="orgId" type="java.lang.Long">

<generator class="native"/>

</id>

<property name="parentorgid" column="parentOrgId" type="java.lang.Long" not-null="true" />

<property name="orgname" column="orgName" type="java.lang.String" not-null="true" />

<property name="orgfullname" column="orgFullName" type="java.lang.String" />

<property name="orglevel" column="orgLevel" type="java.lang.Integer" not-null="true" />

<property name="state" column="state" type="java.lang.Byte" not-null="true" />

<property name="description" column="description" type="java.lang.String" />

<property name="creator" column="creator" type="java.lang.String" />

<property name="createtime" column="createTime" type="java.util.Date" />

<set name="userSet" inverse="true" lazy="true">

<key column="orgId"/>

<one-to-many class="User"/>

</set>

</class>

</hibernate-mapping>

(3)tbl_user_role

<?xml version="1.0" encoding='UTF-8'?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="com.cotel.netvote.dao.model">

<class name="UserRole" table="tbl_user_role">

<id name="urid" column="urId" type="java.lang.Integer">

<generator class="native"/>

</id>

<many-to-one name="role" column="roleId" class="Role" not-null="true" />

<many-to-one name="user" column="loginName" class="User" not-null="true" />

</class>

</hibernate-mapping>

(4)tbl_ role

<?xml version="1.0" encoding='UTF-8'?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="com.cotel.netvote.dao.model">

<class name="Role" table="tbl_role">

<id name="roleid" column="roleId" type="java.lang.Integer">

<generator class="native"/>

</id>

<property name="rolename" column="roleName" type="java.lang.String" not-null="true" />

<property name="createdate" column="createDate" type="java.util.Date" not-null="true" />

<property name="description" column="description" type="java.lang.String" />

<set name="userRoleSet" inverse="true" lazy="true" cascade="all">

<key column="roleId"/>

<one-to-many class="UserRole"/>

</set>

</class>

</hibernate-mapping>




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