天天看点

【Hibernate】3.hibernate映射

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.String string Varchar
int int int
char character char(1)
boolean boolean boolean
java.lang.String text text
byte[] binary blob
java.sql.Date date date
java.sql.Timestamp timstamp timstamp

    数据库提供的主键生成机制,一般是通过一个内部表保存当前主键状态(如对自增型主键,保存的是当前的最大值和递增量),操作时,先读取最大值,然后加上递增量,作为新的主键,更新到内部表中。   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映射

继续阅读