Hibernete 配置及 HQL 语法查询

来源:互联网 发布:cs5463数据手册 编辑:程序博客网 时间:2024/05/17 04:32

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 outerjoin 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 onefetch join. You can however fetch "one" references in addition, as this sample from theHibernate 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 onefetch-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 instrumentHibernate users should learn how to leverage, as it allows tuning thefetch 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>