【Hibernate】3.hibernate映射

来源:互联网 发布:淘宝在哪里买装修模板 编辑:程序博客网 时间:2024/06/05 20:29
Hibernate O/R映射(实体映射)
    实体映射作为类与表之间的联系纽带。
1.实体映射基础(Hibernate中类/表映射、属性/字段映射的基本技术)
    类表映射主要包括:
    a)表名——类名映射:<class name="" table="">...</class>
    b)主键映射:<id name="" column="" type=""><generator class=""/></id>
①.id标签,标识符,自动增加,一般不会对其操作(包括删除、修改等)。
name="id" 声明了Java属性的名字 - Hibernate会使用getId()和setId()来访问它。 column属性则告诉Hibernate, 我们使用EVENTS表的哪 个字段作为主键。
嵌套标签generator说明id生成策略。一般为native。
②.generator元素用来设定标识符生成器,hibernate提供了多种内置的实现。
   increment      由Hibernate自动以递增的方式生成标识符,每次增量为1.   identity   由底层数据库生成标识符,前提是底层数据库支持自动增长字段类型。   sequence   hibernate根据底层数据库的序列生成标识符,前提是底层数据库支持序列。   hilo    native   根据底层数据库对自动生成标识符的支持能力,选择identity、sequence或hilo。   uuid.hex   hibernate采用128位的UUID算法来生成标识符。   assigned   由java应用程序来生成标识符。
     c)字段映射:<property name="" type="" column=""/>
  ①.是除id外声明其他属性所需标签,对于一些非保留关键字属性可以直接映射成为相同名称的字段。type有时可省略,此时Hibernate会试着去确定转换类型和映射类型,但可能出现转换错误。
Java类型Hibernate类型SQL类型java.lang.StringstringVarcharintintintcharcharacterchar(1)booleanbooleanbooleanjava.lang.Stringtexttextbyte[]binaryblobjava.sql.Datedatedatejava.sql.Timestamptimstamptimstamp

    数据库提供的主键生成机制,一般是通过一个内部表保存当前主键状态(如对自增型主键,保存的是当前的最大值和递增量),操作时,先读取最大值,然后加上递增量,作为新的主键,更新到内部表中。
 
2.高级映射技术(自定义数据类型、复合主键,特殊字段的相关映射技术)
    a)自定义数据类型(????)
    b)复合主键(???)
    c)Blob、Clob字段的映射:(???)
 
3.实体映射策略??
 
4.延迟加载
对于Query接口的list()方法与iterator()方法来说,都可以实现查询,但是list()返回的每个对象都是完整的(对象中的每个属性都被表中的字段填充了),而iterator()方法返回的对象中仅仅包含了主键值,只有当对iterator()中的对象进行操作时,Hibernate才会向数据库再次发送查询语句获取该对象的属性值,所有list()方法的效率更高。所有iterator()这种形式叫做延迟加载。
cascade属性值描述none在保存、更新或删除当前对象时,忽略其他关联对象。是默认值save-update当通过Session的save()、update()以及saveOrUpdate()方法来保存或更新当前对象时,级联保存所有关联的新建的临时对象,并级联更新所有关联的游离对象。delete当通过Session的delete()方法删除当前对象时,级联删除所有关联对象。all包含save-update及delete的行为。对当前对象执行evict()或lock()操作时,对关联的持久化对象也会执行相同的操作。delete-orphan删除所有和当前对象解除关联关系的对象。all-delete-orphan包含all和delete-orphan的行为。

5.Hibernate检索策略
5.1.立即检索策略:  即lazy=''false"
            在一对多关联级别中一般使用延迟检索
默认立即检索策略的缺点
    1).select语句的的数目太多,需要频繁的访问数据库,会影响检索性能。
        如需查询n个所需对象,则需执行n+1次select查询语句。这种检索策略没有利用SQL的连接查询。在一对多中,若无需访问关联对象,则加载关联对象会耗费内存。

5.2.延迟检索策略:  即lazy=''true"

优点:由应用程序决定需要加载那些对象,可避免执行多余的select语句,以及避免加载应用程序不需要访问的对象,提高了检索性能,并节省了内存空间。

缺点:应用程序若想访问游离状态的代理类实例,必须保证在持久化状态时已被初始化。

适用范围:

一对多或者多对多关联

5.3左外连接检索策略

默认情况下,多对一关联级别使用左外连接检索策略

优点:a.对应用程序完全透明,不管对象处于持久化还是游离状态,应用程序都可以方便的从一个对象导航到与他关联的对象。

            b.使用了外连接,select语句数目少。
缺点:a.可能回加载应用程序不需访问的对象,浪费内存;
            b.复杂的数据库表也会影响检索性能。
适用范围:
            a.多对一或者一对一关联。
            b.应用程序需立即访问的对象;
            c.数据库系统具有良好的表连接性能。



6.数据关联
 6.1一对一关联<one-to-one>
    (1)主键关联:两张关联表通过主键形成一对一映射关系。cascade 级联,默认使用了左外连接的策略(即fetch=“join”,fetch=“select”表示使用立即检索,即默认是立即加载,两条单独的select语句,若要修改为延迟加载,则需为<one-to-one>标签添加属性constrained=“”,在主控方添加lazy=“true”)(待加载一方)。
主控方:                                                                                                                                       <class name="A" table="t_a">                                                                 <id name="" column="" type="">                                                                                  <generator class="native"/>                                                </id>                                                                                                                                      <property name=""/>                                                                          <one-to-one name="b" class="B" cascade="all"/>                           </class>

被控方:                                                                                                                                       <class name="B" table="t_b">                                                                 <id name="" column="" type="">                                                                                   <generator class="foreign">   
          <param name="property">a</param>                                                                       </generator> foreign主键生成
</id> <property name=""/> <one-to-one name="a" class="A" constrained="true"/>constrained约束 </class>

由于采用了主键关联方式,则通过主键关联的两张表,其关联记录的主键值须保持同步。
 
    (2)唯一外键关联:由<many-to-one>节点定义,唯一外键关联的一对一关系只是多对一关系的一个特例。
//主控方:                                                                                                                                                                                         <class name="A" table="t_a">                                                                <id name="" column="" type="">                                                             <generator class="native"/>    </id>                                                                                                                          <property name=""/>                                                                                             <many-to-one name="b" class="B" column="" unique="true"/>                      </class> 

//被控方:<class name="B" table="t_b">    <id name="" column="" type=""><generator class="native">    <param name="property">a</param></generator>    </id>    <property name=""/>    <one-to-one name="a" class="A" property-ref="b"/></class>

        当只有主控方的时候是单向关系,当被控方中也有一个属性是主控方类型的,则形成了双向关联。
 
 6.2一对多关联
    (1)单向一对多关系:只需在“一”方进行配置。
主控方:                                                                                                                                 <class name="A" table="t_a" dynamic-update=“true” dynamic-insert=“true”> dynamic级联更新     <id name="" column="" type="">                                                                                                      <generator class="native"/>                                                                                                        </id>                                                                                                                                           <property name=""/>                                                                                                                   <set name="b" table="t_b" cascade="all' order-by="">                                                                      <key column=""/>                                                                                                                      <one-to-many class="B"/>                                                                                                     </set>                                                                                                                                       </class>   
        
由于是单向关联,为了保持关联关系,只能通过主控方对被控方进行级联更新。
但更新时会存在id空问题。
 
    (2)双向一对多关系:需要在关联双方均加以配置。
Hibernate中的延迟加载,当我们在程序中获取到了“一”的一方,但是不需要多的一方,则可以使用延迟加载。
        是“一对多”与“多对一”关联的组合,在主控方配置单向一对多关系的基础上,在被控方配置与其对应的多对一关系。
主控方:                                                                                                                                                                                                                   <class name="A" table="t_a" dynamic-update=“true” dynamic-insert=“true”>       <id name="" column="" type="">                                                                            <generator class="native"/>    </id>                                                                                                                            <property name=""/>                                                                                            <set name="b" table="t_b"  inverse="true" inverse控制方向反转         cascade="all' lazy="false" order-by="">                                                                                                                                                                          <key column=""/>                                                                                                                                                                                                   <one-to-many class="B"/>                                                                                                                                                                                               </set>                                                                                                                                                                                                                                                    </class> 

被控方:<class name="B" table="t_b" dynamic-update=“false” dynamic-insert=“false>   <id name="" column="" type="">     <generator class="native">        <param name="property">a</param>     </generator>   </id>   <property name=""/>   <many-to-one name="a" class="A" update="true" insert="true" cascade="none".../></class>

主控方的inverse被设为“true”,将不是主控方,将关联关系的维护工作交给了管理对象B来完成。即关联关系中inverse=“false”的为主控方。

6.3多对多关联
    需要借助中间表完成多对多映射信息的保存。应避免使用,根据情况采取延迟加载来避免无谓的性能开销。 
<class name="com.xx.xxx.Student" table="tb_student">    <id name="id" column="id" type="string">           <generator class="uuid"/>    </id>    <property name="name" column="name" type="string"/>    <set name"courses" table="student_course" cascade="save-update">        <key column="student_id"/>        <many-to-many class="com.xx.xxx.Course" column="course_id"/>    </set></class>
注意:其中set标签中table表示中间表自动生成,cascade表示级联,key标签表示中间表中与当前表关联的列,<many-to-many> 中class表示当前表与另一个表的多对多关系,column表示中间表中与另一个表关联的列

6.4.Map 映射
6.4.1.Map键值对——值为简单类型变量
<class name="com.xx.xxx.Team" table="team">    <id name="id" column="id" type="string">           <generator class="uuid"/>    </id>    <property name="name" column="name" type="string"/>    <map name"students" table="student">        <key column="team_id"/><index column="name" type="string">key值</index>//指定的是map中的key值
        <element column="description" type="string">value值</element>//指定的是map中的value值
</map>
</class>


 6.4.2.Map键值对——值为对象类型变量
<class name="com.xx.xxx.Team" table="team">    <id name="id" column="id" type="string">           <generator class="uuid"/>    </id>    <property name="name" column="name" type="string"/>    <map name"students" table="student" cascade="all">        <key column="team_id"/><index column="card_id" type="string">key值</index>        <one-to-many class="com.xx.xxx.Student" />    </map></class>

<class name="com.xx.xxx.Student" table="student">    <id name="id" column="id" type="string">           <generator class="uuid"/>    </id>    <property name="name" column="name" type="string"/>
    <property name="age" column="age" type="int"/>
    <property name="cardId" column="card_id" type="string"/>
<many-to-one name="team" column="team_id" class="com.xx.xxx.Team"/>
</class>

6.5.Set 映射
<class name="com.xx.xxx.Team" table="team">    <id name="id" column="id" type="string">           <generator class="uuid"/>    </id>    <property name="name" column="name" type="string"/>    <set name"students" table="student">        <key column="team_id"/>        <element column="name" type="string" />    </set></class>
Map与Set标签中的elecment子标签映射的是原子类型,即能够直接映射到数据库表字段上的类型,而one-to-many映射的是实体类型。

6.6.List映射
<class name="com.xx.xxx.Team" table="team">
    <id name="id" column="id" type="string">
           <generator class="uuid"/>
    </id>
    <property name="name" column="name" type="string"/>
    <list name"students" table="student" cascade="all">
        <key column="team_id"/>
<index column="index" ></index>
        <ont-to-many calss="com.xx.xxx.Student" />
    </list>
</class>
其中<index>标签指定list中的顺序,<list>标签中“一”的一方不能添加invalse=“true”,因为在<index>标签有序,不能将维护交给关联方。

6.7.Bag映射
    结合了List和Set,可以重复且没有顺序的一种集合,是由Hibernate提供的。
    Hibernate使用LIst来模拟Bag,相对于List,少了<index>标签
<class name="com.xx.xxx.Team" table="team">    <id name="id" column="id" type="string">           <generator class="uuid"/>    </id>    <property name="name" column="name" type="string"/>    <bag name"students" table="student" cascade="all" inverse="true">        <key column="team_id"/>        <ont-to-many calss="com.xx.xxx.Student" />    </bag></class>

6.8.联合主键映射规则
两种实现方式分别为:将联合主键与其他属性放在同一类中;或者是将联合主键提取放在单独类中
        1).实体类:类中的每个主键属性都对应数据表中的主键列,Hibernate要求具有联合主键的实体类实现Serializable接口,并重写hashCode()方法和equals()方法,重写这两个方法的原因在于Hibernate要根据数据库的联合主键来判断某两行记录是否是一样的,若一样,则为同一个对象,若不同,则为两个对象,这反映到程序中就是根据haseCode与equals方法来判断某两个对象是否能够放到诸如Set这样的集合中。实现Serializable接口的原因在于使用get或load方法的时候需要先构建出来该实体的对象,并且将查询依据(联合主键)设置进去,然后作为get或load方法的第二个参数传递进去即可。

        2).映射文件:
<class name="com.xx.xxx.Student" table="tb_student">    <composite-id>        <key-property name="cardId" column="card_id" type="string" />        <key-property name="name" column="name" type="string" />    </composite-id>    <property name="age" column="age" type="int"/></class>

<class name="com.xx.xxx.Student" table="tb_student">    <composite-id name="studentPrimaryKey" class="com.xx.xxx.studentPrimaryKey">        <key-property name="cardId" column="card_id" type="string" />        <key-property name="name" column="name" type="string" />    </composite-id>    <property name="age" column="age" type="int"/></class>

6.9.组件映射
在一个类中包含另一个类
<class name="com.xx.xxx.Student" table="tb_student">    <id name="id" column="id" type="string">           <generator class="uuid"/>    </id>    <property name="name" column="name" type="string"/>    <component name"address" class="com.xx.xxx.Adress">        <property name="homeAddress" type="string"/>        <property name="schoolAddress" type="string"/>    </component></class>

6.10.继承映射
1).每个子类一张表:每个子类一个hbm文件,父类没有hbm映射信息。即父类没有对应的表,父类中的字段相应的加在了每个子类中。
        2).一张表存储继承体系中的所有类的信息:即将继承体系中的所有字段放在一张表中。
                需要在hbm文件中增加<discriminator column="" type=""></discriminator >,区分子类等信息。
<class name="com.xx.xxx.Person" table="person">    <id name="id" column="id" type="string">           <generator class="uuid"/>    </id>    <discriminator column="personType" type="String"/>    <property name="name" column="name" type="string"/>    <subclass name"com.xx.xxx.Student" discriminator-value="student">        <property name="cardId" type="string"/>    </subclass>    <subclass name"com.xx.xxx.Teacher" discriminator-value="teacher">        <property name="salary" type="int"/>    </subclass></class>

3).公共信息放在父类表中,独有信息放在了子类表中,每个子类对应一张表。查询等操作需涉及两张表。
<class name="com.xx.xxx.Person" table="person">    <id name="id" column="id" type="string">           <generator class="uuid"/>    </id>    <property name="name"  type="string"/>    <joined-subclass name"com.xx.xxx.Student" discriminator-value="student">        <key column="id"/>        <property name="cardId" type="string"/>    </joined-subclass>    <joined-subclass name"com.xx.xxx.Teacher" discriminator-value="teacher">        <key column="id"/>        <property name="salary" type="int"/>    </joined-subclass></class>

6.10.关联映射
要考虑到关联方向(directionality),阶数(multiplicity)和集合(collection)的行为
6.10.1.单向Set-based的关联
用Java的集合类(collection):Set,因为set 不包含重复的元素及与我们无关的排序。
对于多对多关联(或叫n:m实体关系), 需要一个关联表(association table)。
<set name="events" table="person_event">    <key column="person_id"/>    <many-to-many column="event_id" class="events.Event"/></set>
其中name是该类中的一个属性,对应于一个关联表,表名是由set元素的table属性配置的。前者用<key>,后者用<many-to-many>元素的column属性定义。同时告知其所在的类。
值类型的集合
<set name="emailAddresses" table="person_email_addr">    <key column="person_id"/>    <element column="email_addr" type="string"/></set>
比较这次和此前映射的差别,主要在于element部分,这次并没有包含对其它实体引用的集合,而是元素类型为String的集合(在映射中使用小写的名字”string“是向你表明它是一个Hibernate的映射类型或者类型转换器)。和之前一样,set元素的table属性决定了用于集合的表名。key元素定义了在集合表中外键的字段名。element元素的column属性定义用于实际保存String值的字段名。
 
6.10.2.双向关联
首先把集合加入到相应的实体类中。然后再映射文件中修改配置;
<set name="participants" table="person_event" inverse="true">    <key column="person_id"/>    <many-to-many column="person_id" class="events.Person"/></set>
与单向关联的区别是射文件里增加了set元素的inverse="true"属性
 
所有的双向关联需要有一端被设置为inverse。在一对多关联中它必须是代表多(many)的那端。而在多对多(many-to-many)关联中,你可以任意选取一端,因为两端之间并没有差别。


</class>
6.7.Bag映射
原创粉丝点击