【Hibernate】3.hibernate映射

本文详细介绍了Hibernate中实体映射的基础与高级技术,包括类/表映射、属性/字段映射、复合主键、数据关联等核心概念及其配置方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.StringstringVarchar
intintint
charcharacterchar(1)
booleanbooleanboolean
java.lang.Stringtexttext
byte[]binaryblob
java.sql.Datedatedate
java.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映射
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值