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
Hibernate中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。
obj.getMySet().iterator().next();
MyObject obj = session.createQuery(
"from MyObject mo left join fetch mo.mySet").uniqueResult();
obj.getMySet().iterator().next();
from eg.Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens
如果HQL使用了連接,但是沒有使用fetch關鍵字,則生成的SQL語句雖然有連接,但是並沒有取連接表的數據,還是需要單獨的sql取數據,也就是 select a,b,d...中沒有連接表的字段
6、如果集合被聲明爲lazy=true,在HQL中如果顯式的使用 join fetch 則延遲加載失效。
7、在one-to-many的one端顯式設置fecth="join",則無論如何都採取預先抓取(生成一個SQl),延遲加載失效(生成兩個SQL)
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"> 不是外鍵關聯
一對一:
- <?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 package="com.reiyen.hibernate.domain">
- <class name="IdCard" table="id_card">
- <id name="id">
- <!-- id_card的主鍵來源person,也就是共享idCard的主鍵 -->
- <generator class="foreign">
- <param name="property">person</param>
- </generator>
- </id>
- <property name="authorizeDate" column="authorize_date" />
- <!-- one-to-one標籤的含義,指示hibernate怎麼加載它的關聯對象,默認根據主鍵加載,
- constrained="true", 表明當前主鍵上存在一個約束,id_card的主鍵作爲外鍵參照了person -->
- <one-to-one name="person" constrained="true"></one-to-one>
- </class>
- </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 多對多雙向關聯配置舉例
一、模型介紹
|
|
一個人可對應多個地址,一個地址也可以對應多個人。
|
|
二、實體(省略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>