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>