8hbm.xml详解

1对象/关系数据库映射文件
对象和关系数据库之间的映射通常用一个.hbm.xml文档来定义的。例如:
<?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="包名"> 
<class name="类名" table="表名">
           <id name="主键在java类中的字段名" column="对应表中字段" type="类型">
               <generator class="主键生成策略"/>
           </id>
          ……
    </class>
</hibernate-mapping>
hibernate主键生成策略有如下几种:
assigned,主键由外部程序负责生成,在save()之前指定。


hilo,通过hi/lo 算法实现的主键生成机制,需要额外的数据库表或字段提供高位值来源。


seqhilo,与hilo 类似,通过hi/lo 算法实现的主键生成机制,需要数据库中的 Sequence,适用于支持 Sequence 的数据库,如Oracle。


increment,主键按数值顺序递增。此方式的实现机制为在当前应用实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为主键。这种方式可能产生的问题是:不能在集群下使用。


identity,采用数据库提供的主键生成机制,需要把字段定义成自增型。如DB2、SQL Server、MySQL 中的主键生成机制。 


sequence,采用数据库提供的 sequence 机制生成主键。如 Oralce 中的Sequence。


native,由 Hibernate 根据使用的数据库自行判断采用 identity、hilo、sequence 其中一种作为主键生成方式。


uuid.hex,由 Hibernate 基于128 位 UUID 算法 生成16 进制数值(编码后以长度32 的字符串表示)作为主键


uuid.string,与uuid.hex 类似,只是生成的主键未进行编码(长度16),不能应用在 PostgreSQL 数据库中。


foreign,使用另外一个相关联的对象的标识符作为主键。 
主键配置举例如下:
<id name="id" column="id" type="java.lang.Integer">
             <generator class="native"/>
</id>


hibernate-mapping元素:
hibernate-mapping元素的属性,都是可选的:
<hibernate-mapping
    schema="schemaName"
    catalog="catalogName"
    default-cascade="cascade_style"
    default-access="field|property|ClassName"
    default-lazy="true|false"
    auto-import="true|false"
    package="package.name"/>
schema,数据库schema的名称。
catalog,数据库catalog的名称。
schema和catalog属性,指明了这个映射所连接的表所在的schema和catalog的名称,假若指定了这个属性,表名会加上所指定的schema和catalog的名字扩展为全限定名。假若没有制定,表名就不会使用全限定名。


default-cascade(默认为none),默认的级联风格。


default-access(默认为property),Hibernate用来访问所有属性的策略。


default-lazy(默认为true),指明了未明确注明lazy属性的java属性和集合类,hibernate采取什么样的默认加载风格。


auto-import(默认为true),制定我们是否可以在查询语言中使用非全限定的类名。(仅限于本映射文件中的类)


package(可选),指定一个包前缀,如果在映射文档中没有制定全限定的类名,就使用这个包名。
hibernate-mapping元素允许你嵌套多个<class>映射,但最好的做法是一个持久化类对应一个映射文件。


class元素
name,持久化类(或接口)的java全限定名,如果这个属性不存在,hibernate将假定这是一个非POJO的实体映射。


table,默认是类的非全限定名,对应的数据库表名。




property元素
它的各属性中比较常用的有:name(对应的java类的属性名称),column(对应的表中的字段),type(属性的类型,如:java.lang.String),not-null(设置该属性是否为空,为true时表示非空,默认为false)和length(字段的长度限制)。
<!ELEMENT property (meta*,(column|formula)*,type?)>
                      <!ATTLIST property name CDATA #REQUIRED>
                      <!ATTLIST property node CDATA #IMPLIED>
                      <!ATTLIST property access CDATA #IMPLIED>
                      <!ATTLIST property type CDATA #IMPLIED>
                      <!ATTLIST property column CDATA #IMPLIED>
                      <!ATTLIST property length CDATA #IMPLIED>
                      <!ATTLIST property precision CDATA #IMPLIED>
                      <!ATTLIST property scale CDATA #IMPLIED>
                      <!ATTLIST property not-null (true|false) #IMPLIED>
                      <!ATTLIST property unique (true|false) "false">
                      <!ATTLIST property unique-key CDATA #IMPLIED>
                      <!ATTLIST property index CDATA #IMPLIED>  
              <!-- include the columns spanned by this property in an index -->
                      <!ATTLIST property update (true|false) #IMPLIED>
                      <!ATTLIST property insert (true|false) #IMPLIED>
                      <!ATTLIST property optimistic-lock (true|false) "true">  
              <!-- only supported for properties of a class (not component) -->
                      <!ATTLIST property formula CDATA #IMPLIED>
                      <!ATTLIST property lazy (true|false) "false">
     <!ATTLIST property generated (never|insert|always) "never">
例如:
//属性为accessname,对应的列名为accessName,类型(java类型)为String,不可以为null
<property name="accessname" column="accessName" type="java.lang.String" not-null="true" />


//属性为state,对应的列名为state,类型为Byte,不可以为null
<property name="state" column="state" type="java.lang.Byte" not-null="true" />


Byte类型生成tinyint
Long类型生成bigint
Integer类型生成int
String类型生成varchar


2一对多关系(<many-to-one/>和<set></set>)
一对多关系一般用在一个表与另外一个表存在外键关联的时候,例如,用户表的机构id与机构表存在外键关联,则"一"方为组织表,"多"放为用户表,因为一个机构可以包含多个用户,而一个用户只能属于一个机构。


对于存在一对多关系和多对一关系的双方,需要在hbm.xml中进行相应配置,这时在"一"方(例如:机构)需要在映射文件中添加<set></set>元素,因为它包含多个"多"方(User)的对象,一般格式如下:
<set name="java映射类中对应的属性" inverse="true" lazy="true">
<key column="表中对应字段"/>
       <one-to-many class="多方的类"/>
</set>
例如:
//inverse="true"表示机构类不维护主外键关系了,这个任务就交给了User类
<set name="userSet" inverse="true" lazy="true">
          <key column="orgId"/>
<one-to-many class="User"/>
</set>
一般建议在一对多双向关联关系中:将一方的inverse属性设置为true,即将主外键的关系交由多方来维护。如果为false则由"一"方来维护。
这里的 <key column="orgId"/>中的column取值应该与"多方"的<many-to-one name="org" column="orgId" .../>的column取值保持一致


"多"方(例如:用户)只属于一个"一"方对象,一般格式如下:
<many-to-one name="java映射类中对应的属性" column="表中对应字段" class="类名" not-null="true" />
例如:
<many-to-one name="org" column="orgId" class="Organization" not-null="true" />


一对一关系<one-to-one../>)
一对一关系相对于一对多关系来说比较少见,例如一个用户的基本信息表(USER)和一个用户的密码表(PASSWD)就存在一对一的关系,下面是一对一关系在hibernate的配置:
<one-to-one name="主表对象中子表对象的属性名" class="子表对象的类名" cascade="save-update"/>
例如:主表user中的配置
<one-to-one name="password" class="com.amigo.dao.pojo.Passwd" cascade="save-update"/>


子表(用户的密码表)的配置如下:
<one-to-one name="子表对象中主表对象的属性名" class="主表对象的类名" constrained="true" />
<one-to-one name="user" class="com.amigo.dao.pojo.User " constrained="true" />




多对多关系<many-to-many/>
在数据库设计时,一般将多对多关系转换为两个一对多(或多对一)关系。例如在基于角色的权限系统中,用户和角色存在关系就是典型的多对多关系,即一个用户可以具有多个角色,而一个角色又可以为多个用户所有,一般在设计时,都会加上一个用户与角色的关联表,该表与用户表以及角色表都存在外键关联。
<set name="java对象的属性名" table="表名" cascade="all" outer-join="false">   
<key column="表的对应字段"/>   
<many-to-many class="另一个表的对象类" column="另一个表的字段"/>   
</set> 
例如:
t_user方:
<set name="roleSet" table="t_user" cascade="all" outer-join="false">   
<key column="roleId"/>   
<many-to-many class="com.amigo.dao.pojo.Role" column="roleId"/>   
</set>  
t_role方:
<set name="userSet" table="t_role" cascade="all" outer-join="false"> 
<key column="roleId"/>   
<many-to-many class="com.amigo.dao.pojo.User" column="roleId"/>  
</set>


下面是用户表(tbl_user),用户_角色关联表(tbl_user_role),角色表(tbl_role)以及机构表(tbl_organization)的实
例:
tbl_user的映射文件user.hbm.xml
<?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="userID" column="userID" type="java.lang.Integer">
             <generator class="native"/>
        </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="organzation" column="orgId" class="Organzation" not-null="true" />
        <set name="userRoleSet" inverse="true" cascade="all-delete-orphan" lazy="true">
            <key column="userID"/>
            <one-to-many class="UserRole"/>
        </set>
   </class>
</hibernate-mapping>
User.java的内容:
public class User {
private Integer userID;
private String name;
private String password;
private String mobile;
private String telephone;
private String email;
private Date createtime;
private Date lastlogintime;
private Date logintimes;
private String description;
private Organzation organzation;
private set<UserRole> userRoleSet=new HashSet<UserRole>();
....
}




tbl_organization的映射文件organzation.hbm.xml
<?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>
Organzation.java的内容:
public class Organzation {
private Long orgid;
private Long parentorgid;
private String orgname;
private String orgfullname;
private int orglevel;
private byte state;
private String description;
private String creator;
private Date createtime;
private Set<User> userSet=new HashSet<User>();
...
}


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="userID" class="User" not-null="true" />
</class>
</hibernate-mapping>
UserRole.java的内容:
public class UserRole {
private Integer urid;
private Role role;
private User user;
...
}




tbl_ role的映射文件role.hbm.xml
<?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>
Role.java的内容:
public class Role {
private Integer roleid;
private String rolename;
private Date createdate;
private String description;
private Set<UserRole> userRoleSet=new HashSet<UserRole>();
...
}


3formula属性
以学生和书本这个One-to-many关系来说明:
学生Students.java映射文件:
    <hibernate-mapping>  
      <class table="T_Students" name="com.hewill.model.Students">  
        <id type="java.lang.String" column="id" length="32" name="id">  
          <generator class="uuid.hex"/>  
        </id>  
        <property name="bookCount" formula="(select count(*) from T_Books )"/>  
        <property name="name" type="java.lang.String" column="name"/>  
        <property name="sex" type="java.lang.String" column="sex"/>  
        <property name="number" type="java.lang.String" column="number"/>  
        <set inverse="true" cascade="all" name="books">  
          <key column="student_id"/>  
          <one-to-many class="com.hewill.model.Books"/>  
        </set>  
      </class>  
    </hibernate-mapping>  


书本Books.java映射文件:
<hibebrnate-mapping>  
  <class table="T_Books" name="com.hewill.model.Books">  
    <id type="java.lang.String" column="id" length="32" name="id">  
      <generator class="uuid.hex"/>  
    </id>  
    <property name="bookname" type="java.lang.String" column="bookname"/>  
    <many-to-one column="student_id" name="studentid" class="com.hewill.model.Students"/>  
  </class>  
</hibernate-mapping>




测试代码:
public static void main(String[] args) {  
        Session session = sessionFacotry.getCurrentSession();  
        Transaction tx = session.beginTransaction();  
          //从Students中查询
        Query query = session.createQuery("from Students where name='liu'");  
        List<Students> list = query.list();  
  
        for(Students students : list){  
            System.out.println("name : "+students.getName());  
            System.out.println("number : "+students.getNumber());  
            System.out.println("bookCount : "+students.getBookCount());  
        }  
        session.close();  



查询结果:
 select  
        students0_.id as id0_,  
        students0_.name as name0_,  
        students0_.sex as sex0_,  
        students0_.number as number0_,  
        (select  
            count(*)   
        from  
            T_Books ) as formula0_   
    from  
        T_Students students0_   
    where  
        students0_.name='liu'  


name : liu  
number : 006  
bookCount : 2 
从hibernate执行的语句中,我们可以看到Students的bookCount属性是formula通过执行指定的"select count(*) from T_Books"来获得的,bookCount字段在数据库表T_Students表中是没有的,它是一个虚拟列。


@Formula注解
@Formula("(select COUNT(*) from user)")  
    private int count;  


注意
<property name="belongOrganN" type="string" insert="false" update="false" formula="(select x.OrganShortN from tsy_organ x where x.OrganID= BelongOrganID)"/> 或
<property name="belongOrganN" type="string" insert="false" update="false">
  <formula><![CDATA[(select x.OrganShortN from tsy_organ x where x.OrganID= BelongOrganID)]]></formula>
</property>
formula="()",里面的是sql语句,字段和表名都应该和数据库相对应,若带有参数如(select x.OrganShortN from tsy_organ x where x.OrganID= BelongOrganID),OrganID是tsy_organID表中的字段,BelongOrganID名称表示当前<property>元素所在的映射文件对应表的字段名。
formula="( sql )",这个括号不能少,不然会报错,我试了几次,没括号就报错,添上就没问题。如:
@Formula("(select x.OrganShortN from tsy_organ x where x.OrganID= BelongOrganID)")  


http://tenn.iteye.com/blog/101892


update="false" 与 insert="false"
<property name="subject" type="java.lang.String" update="false" insert="false" >
          <column name="SUBJECT" length="200"></column>
      </property>
那么这个字段将不被包括在基本的update语句中,修改的时候,将永远不包括 这个字段(insert同理)
 默认设置为update="true" insert="true"   




dynamic动态SQL语句的配置<property>中
      <property name="subject" type="java.lang.String" dynamic-insert="true"  >
          <column name="SUBJECT" length="200"></column>
      </property>
dynamic-insert="true" 表 示insert对象时,生成动态的insert语句,如果这个字段的值为null则不会加到这个insert语句中(update同理)
 默认设置为dynamic-insert="false" dynamic-update="false" 


4继承
在面向对象的程序领域中,类与类之间是有继承关系的,例如Java世界中只需要extends关键字就可以确定这两个类的父子关系,但是在关系数据库的世界中,表与表之间没有任何关键字可以明确指明这两张表的父子关系,表与表是没有继承关系这样的说法的。为了将程序领域中的继承关系反映到数据中,Hibernate为我们提供了3中方案:
第一种方案:一个子类对应一张表。
第二种方案:使用一张表表示所有继承体系下的类的属性的并集。
第三种方案:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。


现在假设有People、Student、Teacher三个类,父类为People,Student与Teacher为People的父类,代码如下:
People.java的代码:
public class People
{
    /*父类所拥有的属性*/
    private String id;
    private String name;
    private String sex;
    private String age;
    private Timestamp birthday;
    
    /*get和set方法*/
}


Student.java的代码:
public class Student extends People
{
    /*学生独有的属性*/
    private String cardId;//学号


    public String getCardId()
    {
        return cardId;
    }


    public void setCardId(String cardId)
    {
        this.cardId = cardId;
    }
}


Teacher.java:
public class Teacher extends People
{
    /*Teacher所独有的属性*/
    private int salary;//工资


    public int getSalary()
    {
        return salary;
    }


    public void setSalary(int salary)
    {
        this.salary = salary;
    }
}
第一种方案:一个子类对应一张表 
该方案是使继承体系中每一个子类都对应数据库中的一张表。每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段。这种策略是使用<union-subclass>标签来定义子类的。
People.hbm.xml文件:
<?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>
    <class name="com.suxiaolei.hibernate.pojos.People" abstract="true">
        <id name="id" type="string">
            <column name="id"></column>
            <generator class="uuid"></generator>
        </id>


        <property name="name" column="name" type="string"></property>
        <property name="sex" column="sex" type="string"></property>
        <property name="age" column="age" type="string"></property>
        <property name="birthday" column="birthday" type="timestamp"></property>


        <!-- 
        <union-subclass name="com.suxiaolei.hibernate.pojos.Student" table="student"> 
            <property name="cardId" column="cardId" type="string"></property> 
        </union-subclass> 
        <union-subclass name="com.suxiaolei.hibernate.pojos.Teacher" table="teacher"> 
            <property name="salary" column="salary" type="integer"></property> 
        </union-subclass> 
        -->
    </class>
    <union-subclass name="com.suxiaolei.hibernate.pojos.Student"
        table="student" extends="com.suxiaolei.hibernate.pojos.People">
        <property name="cardId" column="cardId" type="string"></property>
    </union-subclass>


    <union-subclass name="com.suxiaolei.hibernate.pojos.Teacher"
        table="teacher" extends="com.suxiaolei.hibernate.pojos.People">
        <property name="salary" column="salary" type="integer"></property>
    </union-subclass>
</hibernate-mapping>
以上配置是一个子类一张表方案的配置,<union-subclass>标签是用于指示出该hbm文件所表示的类的子类,如People类有两个子类,就需要两个<union-subclass>标签以此类推。<union-subclass>标签的"name"属性用于指定子类的全限定名称,"table"属性用于指定该子类对应的表的名称,"extends"属性用于指定该子类的父类,


注意该属性与<union-subclass>标签的位置有关,若 <union-subclass>标签作为<class>标签的子标签,则"extends"属性可以不设置,否则需要明确设置"extends"属性。<class>标签中的"abstract"属性如果值为true则不会生成people表结构;如果值为false则会生成people表结构,但是不能向people表插入数据。(如果没有指定table属性的值则生成的表名为类名的第一个字母小写的)根据 People.hbm.xml生成表结构:
drop table if exists student
drop table if exists teacher
 create table student (
        id varchar(255) not null,
        name varchar(255),
        sex varchar(255),
        age varchar(255),
        birthday datetime,
        cardId varchar(255),
        primary key (id)
    )


    create table teacher (
        id varchar(255) not null,
        name varchar(255),
        sex varchar(255),
        age varchar(255),
        birthday datetime,
        salary integer,
        primary key (id)
    )


***************


其实可以将上面的People.hbm.xml分成三个文件:
people.hbm.xml映射文件
<?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>
    <class name="lifecenter.manage.model.jicheng.People" abstract="true">
        <id name="id" type="string">
            <column name="id"></column>
            <generator class="uuid"></generator>
        </id>


        <property name="name" column="name" type="string"></property>
        <property name="sex" column="sex" type="string"></property>
        <property name="age" column="age" type="string"></property>
        <property name="birthday" column="birthday" type="timestamp"></property>
    </class>
</hibernate-mapping>


student.hbm.xml映射文件
<?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>
 <union-subclass name="lifecenter.manage.model.jicheng.Student"
        table="student" extends="lifecenter.manage.model.jicheng.People">
        <property name="cardId" column="cardId" type="string"></property>
   </union-subclass>


</hibernate-mapping>


teacher.hbm.xml映射文件
<?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>
<union-subclass name="lifecenter.manage.model.jicheng.Teacher"
        table="teacher" extends="lifecenter.manage.model.jicheng.People">
        <property name="salary" column="salary" type="integer"></property>
    </union-subclass>
</hibernate-mapping>


使用hibernate union-subclass 元素进行继承映射时会抛出此异常:Cannot use identity column key generation with <union-subclass> mapping for(父类)....
原因是:使用unnion-subclass 元素时 父类的标识属性生成器不能使用"indentity","navtive"这种依靠数据库自己管理id的方式,可以选择"hilo”,"increment”等。因为多个子类的表的id需要被同一管理,如果使用数据库级的id生成策略,则多个子类表的id就没办法同一管理了。
比如:子类A的第一条数据的id为1,那么子类B的第一条数据的id就不能使1,可能是2.
***************


第二种方案:使用一张表表示所有继承体系下的类的属性的并集
这种策略是使用<subclass>标签来实现的。因为类继承体系下会有许多个子类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。Hibernate中的这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。在表中添加这个标示列使用<discriminator>标签来实现。


将继承体系中的所有类信息表示在同一张表中后,只要是这个类没有的属性会被自动赋上null。
配置People.hbm.xml:
<?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>
    <class name="com.suxiaolei.hibernate.pojos.People" table="people">
        <id name="id" type="string">
            <column name="id"></column>
            <generator class="uuid"></generator>
        </id>


        <discriminator column="peopleType" type="string"></discriminator>


        <property name="name" column="name" type="string"></property>
        <property name="sex" column="sex" type="string"></property>
        <property name="age" column="age" type="string"></property>
        <property name="birthday" column="birthday" type="timestamp"></property>


        <subclass name="com.suxiaolei.hibernate.pojos.Student" discriminator-value="student">
            <property name="cardId" column="cardId" type="string"></property>
        </subclass>
        
        <subclass name="com.suxiaolei.hibernate.pojos.Teacher" discriminator-value="teacher">
            <property name="salary" column="salary" type="string"></property>
        </subclass>
    </class>
</hibernate-mapping>
<discriminator> 标签用于在表中创建一个标识列,其"column"属性指定标识列的列名,"type"指定了标识列的类型。<subclass>标签用于指定该HBM文件代表类的子类,有多少子类就有多少个该标签,其"name"属性指定子类的名称,"discriminator-value"属性指定该子类的数据的标识列的值是什么,其"extends"属性与<union-subclass>的"extends"属性用法一致。
<subclass>元素也同<union-subclass>元素一样可以放在<class>外。


根据 People.hbm.xml生成表结构:
drop table if exists people
    create table people (
        id varchar(255) not null,
        peopleType varchar(255) not null,
        name varchar(255),
        sex varchar(255),
        age varchar(255),
        birthday datetime,
        cardId varchar(255),
        salary varchar(255),
        primary key (id)
    )
可以看到一张表将继承体系下的所有信息都包含了,其中"peopleType"为标识列。


第三种方案:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。
这种策略是使用<joined-subclass>标签来定义子类的。父类、子类都对应一张数据库表。在父类对应的数据库表中,它存储了所有记录的公共信息,实际上该父类对应的表会包含所有的记录,包括父类和子类的记录;在子类对应的数据库表中,这个表只定义了子类中所特有的属性映射的字段。子类对应的数据表与父类对应的数据表,通过一对一主键关联的方式关联起来。


people 表中存储了子类的所有记录,但只记录了他们共有的信息,而他们独有的信息存储在他们对应的表中,一条记录要获得其独有的信息,要通过people记录的主键到其对应的子表中查找主键值一样的记录然后取出它独有的信息。
配置 People.hbm.xml:
<?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>
    <class name="com.suxiaolei.hibernate.pojos.People" table="people">
        <id name="id" type="string">
            <column name="id"></column>
            <generator class="uuid"></generator>
        </id>


        <property name="name" column="name" type="string"></property>
        <property name="sex" column="sex" type="string"></property>
        <property name="age" column="age" type="string"></property>
        <property name="birthday" column="birthday" type="timestamp"></property>
        
        <joined-subclass name="com.suxiaolei.hibernate.pojos.Student" table="student">
            <key column="id"></key>
            <property name="cardId" column="cardId" type="string"></property>
        </joined-subclass>
        
        <joined-subclass name="com.suxiaolei.hibernate.pojos.Teacher" table="teacher">
            <key column="id"></key>
            <property name="salary" column="salary" type="integer"></property>
        </joined-subclass>
    </class>
</hibernate-mapping>
<joined- subclass>标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。
<joined-subclass>元素也同<union-subclass>元素一样可以放在<class>外。


根据 People.hbm.xml生成表结构:
    drop table if exists people
    drop table if exists student
    drop table if exists teacher


    create table people (
        id varchar(255) not null,
        name varchar(255),
        sex varchar(255),
        age varchar(255),
        birthday datetime,
        primary key (id)
    )


    create table student (
        id varchar(255) not null,
        cardId varchar(255),
        primary key (id)
    )


    create table teacher (
        id varchar(255) not null,
        salary integer,
        primary key (id)
    )


    alter table student 
        add index FK8FFE823BF9D436B1 (id), 
        add constraint FK8FFE823BF9D436B1 
        foreign key (id) 
        references people (id)


    alter table teacher 
        add index FKAA31CBE2F9D436B1 (id), 
        add constraint FKAA31CBE2F9D436B1 
        foreign key (id) 
        references people (id)
可以看到,父类对应的表保存公有信息,子类对应的表保存独有信息,子类和父类对应的表使用一对一主键关联的方式关联起来。








******************
复合主键
<hibernate-mapping package="K10.entity">
 <class table="organization_target">
  <meta attribute="sync-DAO">false</meta>


  <composite-id>
   <key-property column="organization_target_number" type="int"/>
   <key-property column="organization_target_id" type="int"></key-property>
  </composite-id>
 </class>
 ....
<hibernate-mapping>




*********************
<property>元素的type (optional)属性,它可以取值为hibernate type和java type:
Java Class Attribute Type         Hibernate Type               Possible SQL Type-Vendor Specific


Integer, int, long short          integer, long, short         Appropriate SQL type


char                              character                    char


java.math.BigDecimal              big_decimal                  NUMERIC, NUMBER


float, double                     float, double                float, double


java.lang.Boolean, boolean        boolean, yes_no,             boolean, int,varchar
                                  true_false
  
java.lang.string                  string                       varchar, varchar2


Very long strings                 text                         CLOB, TEXT


java.util.Date                    date, time, timestamp        DATE(只有日期), TIME(只有时间), TIMESTAMP


java.util.Calendar                calendar, calendar_date      TIMESTAMP, DATE


java.util.Locale                  locale                       varchar,varchar2


java.util.TimeZone                timezone                     varchar, varchar2


java.util Currency                Currency                     varchar, varchar2


java.sql.Clob                     clob                         CLOB


java.sql.Blob                     blob                         BLOB


Java object                       serializable                 binary field


byte array                        binary                       binary field


java.lang.Class                   class                        varchar, varchar2


******************
precision属性:
<property name="curMonthtAmount" type="big_decimal">
            <column name="cur_montht_amount" scale="2" precision="13">
                <comment>当月出口金额</comment>
            </column>
</property>

<property name="curMonthtAmount" type="big_decimal" scale="2" precision="13">
            <column name="cur_montht_amount">
                <comment>当月出口金额</comment>
            </column>
</property>
Hibernate 配置文件precision与scale的说法:
Oracle使用标准、可变长度的内部格式来存储数字。这个内部格式精度可以高达38位。
    NUMBER数据类型可以有两个限定符,如:
    column NUMBER (precision, scale)
    precision表示数字中的有效位。如果没有指定precision的话,Oracle将使用38作为精度。
    scale表示数字小数点右边的位数,scale默认设置为0.  如果把scale设成负数,Oracle将把该数字取舍到小数点左边的指定位数。




*********************
inverse
inverse 从词义上看过去可能不是那么容易理解,其实它的意思就是由谁来控制关联关系的自动维护,当 inverse=true 就意味着当前对象是不能自动维护关联关系,当 inverse=false 就意味着当前对象可自动维护关联关系,还是举例来说:


假设 Org 和 User 一对多关联,
当 org 中 getUsers 的 inverse=false 的情况:
org.getUsers().add(user);
dao.save(org);


这样执行后将会看到数据库中 user 这条记录中的 orgId 已经被设置上去了。
当 inverse=true 的情况下,执行上面的代码,会发现在数据库中 user 这条记录中的 orgId 没有被设置上去。inverse 的作用这样可能看的不是很明显,在下面的一对多中会加以描述。


下面是我看到上面的内容而得出的自己的一点理解:
inverse属性是主方(org)的.hbm.xml中 <set> 的一个属性,字面意思“相反,反方向的”,当其为true,即关联关系完全由反方向的子表维护,这样可以减少SQL语句(这点网上达成了共识),主表更新了相关数据不会反映到数据库。


反之,为false时,则主表和子表都维护关联关系,主表更新了数据能反映到数据库。
inverse的默认值为false。


********************
级联策略
在Many与One的关系中,级联策略很重要,这关系着效率与完整性等问题。
在<set>、<many-to-one>、<one-to-one>元素中都有一个cascade属性,它用于指定如何操纵与当前对象关联的其他对象。cascade有如下几个可选属性值:
none:是默认值,在保存、更新、删除当前对象时,忽略其他关联对象。
save-update:当通过Session的save()、update()和saveOrUpdate()保存或更新对象时,级联保存所有关联的新建的临时对象,并且级联更新所有关联的游离对象。
delete:当通过Session的delete()删除当前对象时,级联删除所有关联对象。
all:包含save-update和delete的行为。此外,当对当前对象执行evict()或lock()操作时,也会对所有级联的持久化对象执行evict和lock操作。
delete-orphan:删除所有和当前对象接触关联关系的对象。
all-delete_orphan:包含all和delete-orphan的行为。


delete-orphan(one-to-many)下有效,父亲删掉,孤儿也删掉). 一般对many-to-one, many-to-many不设置级联,在< one-to-one >和< one-to-many >中设置级联
缺省是none,不做任何级联操作。


*****************
也可以在hbm.xml文件中配置命名查询:
<hibernate-mapping>
<class>......</class>
<query name="findGroupsByUser">  
    <![CDATA[ 
    select distinct g 
    from org.jbpm.pvm.internal.identity.impl.MembershipImpl m 
      join m.user u 
      join m.group g 
    where u.id = :userId 
    ]]>  
</query> 
</hibernate-mapping>


Query query = session.getNamedQuery("findGroupsByUser");  
query.setInteger("userId", 25);  
List result= query.list();  




*****************
 最好不要实将体bean的属性命名为properties,否在在进行hql查询时会报错。

























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值