*.hbm.xml文件 hbm解释:hibernate-mapping

映射文件说明

Hibernate-mapping

--类层次:class

         主键:id

         基本类型:property

         实体引用类:many-to-one | one-to-many

         集合:set | list | map | array

                   One-to-one

                   Many-to-many

         子类:subclass|joined-subclass

         其他component | any等

查询语句:query(用来放置查询语句,便于对数据库查询的统一管理和优化)

每个Hibernate-mapping中可以同时定义多个类,但更推荐为每个类都创建一个单独的映射文件

 

 

 

<hibernate-mapping package="com.clou.entity">

    <class name="News" table="news" dynamic-update="true">

       <id name="id">

           <column name="id"></column>

           <generator class="native"></generator>

       </id>

       <property name="title" type="string" />

       <property name="author" type="string" />

       <property name="date" type="date" />

    </class>

</hibernate-mapping>

/**

     * 如果没有在class标签中设置 dynamic-update属性设置为true时,

     * 下面方法运行后会更新除了id的所有字段

     * 如果设置后只会动态的更新修改过的字段值

     * dynamic-insert 属性的设置和这个属性的原理是一样的

     */

    @Test

    public void testDynamicUpdate(){

       News news = (News) session.get(News.class, 1);

       news.setAuthor("ABCD");

    }

 

 

映射对象标识符

Hibernate使用对象标识符(OID)来建立内存中对象和数据库表中记录的对应关系,对象的OID和数据库表的主键对应,Hibernate通过标示符生成器来为主键赋值。

Hibernate推荐在数据表中使用代理主键,即不具备业务含义的字段,代理主键通常为整数类型,因为整数类型比字符串类型要节省更多的数据库空间,

在对象-关系映射文件中,<id>元素用来设置对象标识符,<generator>子元素用来设定标识符生成器。

Hibernate提供了标识符生成器接口:IdentifierGenerator并提供了各种内置实现

 

<hibernate-mapping>hibernate映射文件的跟元素

Default-cascade(默认为none)设置hibernate默认的级联风格,若配置Java属性集合映射时没有指定cascade属性,则Hibernate将采用此处指定的级联风格。

Default-access(默认为property):指定Hibernate的默认的属性访问策略。属性值为property,即使用getter,setter方法来访问属性,若指定access,则Hibernate会忽略getter/setter方法,而通过反射访问成员变量。

Default-lazy(默认为true):设置Hibernate moming的延迟加载策略,该属性值为true,即启用延迟加载策略,若配置Java属性映射,集合映射时没有指定lazy属性,则Hibernate将采用此处指定的延迟加载策略

Package(可选):指定一个包前缀,如果在映射文档中没有指定全限定的类名,就是用这个作为包名。

 

<class>标签 用于指定类和表的映射

Name属性:

Table属性:

Dynamic-insert若设置为true,标识当保存一个对象时,会动态生成insert语句,insert语句中仅包含所有取值不为Null的字段,默认为false.

dynamic-update:若设置为true,表示当更新一个对象时,会动态生成update语句,update语句中仅包含所有取值需要更新的字段,默认值为false.

Batch-size:指定根据OID来抓取实例时,每批抓取的实例数。

Lazy:指定是否延迟加载。

Mutable=”true”

select-before-update=”false”(默认) : 对游离对象采用两种方法,update和 saveOrUpdate(obj)方法有效果 ,先查后在决定是否更新。

 

<id>标签:设定持久化类的OID和表的主键的映射

    name:标识持久化类OID的属性名

    column:设置标识属性所映射的数据表的列名(主键组点的名字)

    unsaved-value:若设置了该属性,Hibernate会通过比较持久化类的OID值和该属性值来区分当前持久化类的对象是否为临时对象。

    type:指定Hibernate映射类型。Hibernate映射类型是Java类型与SQL类型的桥梁。如果没有为某个属性显示设定映射类型,Hibernate会运用反射机制先识别出持久化类的特定属性的Java类型,然后自动使用与之对应的默认的Hibernate映射类型。

Java的基本数据类型和包装类型对应相同的Hibernate映射类型。基本数据类型无法表达null,所以对于持久化类的OID推荐使用包装类型。

 

 

主键生成策略generator

Hibernate提供的内置标识符生成器:

Increment:适用于代理主键,由Hibernate自动以递增方式生成。

Identity:适用于代理主键,由底层数据库生成标识符。

Sequence:适用于代理主键,Hibernate根据底层数据库的序列生成标识符,这要求底层数据库支持序列

Hilo适用于代理主键,hibernate分局high/low算法生成标识符。

Seqhilo:适用于代理逐渐,使用一个高/低算法来搞笑的生成long,short或者int类型的标识符,

Native适用于代理主键,根据底层数据库对自动生成标识符的方式,自动选择identity,sequence 或者hilo

Uuid.hex:适用于代理主键,hibernate采用128位的UUID算法生成标识符。

 

Foreign:适用于代理主键,使用另外一个相关联的对象的标识符。

 

Increment标识符生成器

Increment标识符生成器由Hibernate以递增的方式为代理主键赋值:

         Hinernate先会读取News表中的主键的最大值,而接下来向NEWS 表中插入记录时,就在max(id)的基础上递增,增量为1:所以有并发问题

适用范围:只适用于测试的时候

 

Identity标识符生成器

Identity标识符生成器,由底层数据库来负责生成标识符,它要求底层数据库把主键定义为自动增长字段类型

适用范围:由于identity生成标识符的机制依赖于底层数据库系统,因此,要求底层数据库系统必须支持自动增长字段类型,支持自动增长字段类型的数据库包括:DB2,Mysql,MSSQLServer,Sybase 等不能为Oracle类型

OID必须为long ,int 或short类型,如果把OID定义为byte类型,在运行时会抛出异常。

 

Sequence标识符生成器

Sequence标识符生成器利用底层数据库提供的序列来生成标识符。

<id name=”id”>

         <generator class=”sequence”>

                   <param name=”sequence”>news_seq</param>

         </generator>

</id>

 

 

Hilo标识符生成器

Hilo标识符生成器由Hibernate按照一种high/low算法* 生成标识符,它从数据库的特定表的字段中获取high值

<id name=”id”>

         <generator class=”hilo”>

                   <param name=”table”>hi_table<param>

                   <param name=”column”>next_value</param>

                   <param name=”max_lo”>10</param>

         <generator>

</id>

Hibernate在持久化一个News 对象时 ,由Hibernate负责生成主键值。Hilo标识符生成器在生成标识符时,需要读取并修改hi_table表中的next_value值

适用范围:

         由于hilo标识符机制不依赖于底层数据库系统,因此它适合所有的数据库系统

         OID必须为long, int 或short类型,如果把OID定义为byte类型 ,插入时会抛出异常。

 

Native标识符生成器

Native标识符生成器依据底层数据库对自动生成标识符的支持能力,来选择使用identity , sequence 或 hilo标识符生成器。

适用范围:

适用于跨市平台开发

OID必须为long, int , short 类型, 如果为byte类型 运行时会抛出异常

 

<property>节点

property 元素用于指定类的属性和表字段的映射

         name:指定该持久化类的属性的名字。

         column:指定与类的属性映射的表的字段名,如果没有设置该属性,Hibernate将直接使用类的属性名作为字段名。

         type:指定Hibernate映射类型。Hibernate映射类型是Java类型与SQL类型的桥梁。如果没有为某个属性显示设定映射类型,Hibernate会运用反射机制先识别出持久化类的特定属性的Java类型,然后自动使用与之对应的默认的Hibernate映射类型。

Java的基本数据类型和包装类型对应相同的Hibernate映射类型。基本数据类型无法表达null,所以对于持久化类的OID推荐使用包装类型。

 

Not-null: 若该属性值为true, 表明不允许null,默认为false;

Access:指定Hibernate的默认的属性访问策略、默认为property,即使用getter , setter方法来访问属性,若指定field,则Hibernate会忽略getter/setter方法,而通过反射访问成员变量。

Unique : 设置是否为该属性所映射的数据列添加唯一约束。

Update : 默认为true标识该字段的值可以被修改,如果该属性的值为false时,标识该字段的值不能被修改 ,若修改该字段的值 ,也不会报错,但在数据库中得不到修改后的值(property标签中的update属性)

Index : 指定一个字符串的索引名称,当系统需要Hibernate自动创建表时,用于为该属性所映射的数据列创建索引,进而加快该数据列的查询。

Length:

 

formula: 设置一个SQL表达式,Hibernate将根据它来计算出派生属性的值。

派生属性:并不是持久化类的所有属性都直接和表的字段匹配,持久化类的有些属性的值必须在运行时通过计算才能得出来,这些属性称为派生属性。

使用formula属性时,

formula=”(sql)”的英文括号不能少。

sql表达式中的列名和表名都应该和数据库对应,而不是和持久化对象的属性对应

如果需要在formula属性中使用参数,这直接使用where cur.id = id 形式,其中id就是参数,和当前持久化对象的id属性对应的列的id值将作为参数传入。

 

public class News {

    private Integer id;

    private String title;

    private String author;

    private Date date;

   

    //该属性值为: title:author

    private String desc;

   

 

<hibernate-mapping package="com.clou.entity" >

    <class name="News" table="news" dynamic-update="true">//动态更新,只根据已有的字段生成更新语句

       <id name="id">

           <column name="id"></column>

           <generator class="native"></generator>

       </id>

       <property name="title" type="string" />

       <property name="author" type="string" />

       <property name="date" type="date" />

       <!-- 映射派生属性 -->

       <property name="desc" formula="(select concat(author,':',title) from news n where n.id = id)">

       </property>

    </class>

</hibernate-mapping>

 

 

映射Java的时间日期类型:

1)  两个基础知识:

I       在Java中,代表时间和日期的类型包括:java.util.Date和java.util.Calendar

此外,在JDBC API中还提供了3个扩展了java.util.Date类的子类:java.sql.Date

Java.sql.Time 和java.sql.Timestamp , 这三个类分别和标准SQL类型中的

DATE , TIME , 和 TIMESTAMP类型对应

II,在标准SQL中,DATE 类型表示日期,TIME 类型表示时间,TIMESTAMP类型表示时间戳,同时包含日期和时间信息

 

2)  如何进行映射?

因为java.util.Date是java.sql.Date,Java.sql.Time 和java.sql.Timestamp 类的父类 ,所以java.util.Date可以对应标准SQL类型中的DATE , TIME , 和TIMESTAMP

基于I,所以在设置持久化类的Date类型时,设置为java.util.Date. 因为java.util.Date可以映射java.sql中的任何日期类型

如何把java.util.Date映射为DATE , TIME , 和TIMESTAMP ?

可以通过property的type属性类进行映射:

例如

<property name=”date” type=”date”>

         <column name=”DATE”/>

</property>

<property name=”date” type=”time”>

         <column name=”DATE”/>

</property>

 

<property name=”date” type=”timestamp”>

         <column name=”DATE”/>

</property>

其中timestamp , date , time 即不是Java类型,也不是标准SQL类型,而是hibernate映射类型。

以下情况下必须显示指定Hibernate映射类型

一个Java类型可能对应多个Hibernate映射类型,例如:如果持久化类的属性为java.util.Date类型,对应的Hibernate映射类型可以是date , time , 或timestamp。

此时必须根据对应的数据表的字段的SQL类型,来确定Hibernate映射类型,如果字段为DATE类型,那么hibernate映射类型为date, 如果字段为TIME类型,那么Hibernate映射类型为time,如果字段为TIMESTAMP类型,那么Hibernate映射类型为timestamp。

 

Java大对象类型的Hibernate映射

在Java中,java.lang.String 可用于表示长字符串(长度超过255),字节数组byte[] 可用于存放图片或文件的二进制数据。此外,在JDBC API中海提供了 java.sql.Clob和java.sql.Bolb类型,它们分别和标准SQL中的CLOB 和BOLB类型对应,CLOB表示字符串大对象(Character Large Object), BLOB表示二进制对象(Binary Large Object)

映射类型                 binary                text                              clob                    blob

Java类型                            byte[]                 java.lang.String        java.sql.Clob    java.sql.Blob

标准SQL类型 varchar(或BLOB)CLOB                      CLOB                  BLOB

MYSQL类型              BLOB                  CLOB                           CLOB                  BLOB

Oracle类型               BLOB                  CLOB                           CLOB                  BLOB

 

Mysql不支持标准SQL的CLOB类型,在Mysql中,用TEXT , MEDIUMTEXT及LONGTEXT类型来表示长度操作255的长文本数据

在持久化类中,二进制大对象可以声明为byte[]或java.sql.Blob类型;字符串可以声明为java.lang.String 或jva.sql.Clob

实际上在Java应用程序中处理长度超过255的字符串,使用java.lang.String比java.sql.Clob更

 

public class News {

    private Integer id;

    private String title;

    private String author;

    private Date date;

   

    //该属性值为: title:author

    private String desc;

   

    //大文本类型

    private String content;

   

    //二进制数据

    private Blob image;

   

<class name="News" table="news" dynamic-update="true">

       <id name="id">

           <column name="id"></column>

           <generator class="native"></generator>

       </id>

       <property name="title" type="string" />

       <property name="author" type="string" />

       <property name="date" type="date" />

       <!-- 映射派生属性 -->

       <property name="desc" formula="(select concat(author,':',title) from news n where n.id = id)">

       </property>

       <!-- 映射大对象-->

       <!-- <property name="content" type="clob"></property> -->

       <!--

            如果使用这种方式生成数据库的表 该字段的type类型是longtext类型如果想

           若希望精确映射SQL 类型, 可以使用 sql-type属性

        -->

        <property name="content" >

           <column name="CONTENT" sql-type="mediumtext"></column>

        </property>

       <!-- <property name="image" type="blob"></property>-->

       <property name="image">

           <column name="IMAGE" sql-type="mediumblob" />

       </property>

    </class>

 

    @Test

    public void testBlob() throws IOException, SQLException{

       News news = new News();

       news.setAuthor("cc");

       news.setContent("CONTENT");

       news.setDate(new Date());

       news.setDesc("DESC");

       news.setTitle("CC");

       //该图片存放在项目下,得到一个输入流把它写出去

       InputStream stream = new FileInputStream("Hydrangeas.jpg");

       //保存时需要借助Hibernate的getLobCreator() 的createBlob方法

       Blob image = Hibernate.getLobCreator(session)

                           .createBlob(stream, stream.available());

       news.setImage(image);

       session.save(news);

       InputStream in = image.getBinaryStream();

      

       System.out.println(in.available());//得到的是文件的大小

      

    }

    @Test

    public void testhuoquBlob(){

       //上面测试的是保存,这个方法测试获取Blob对象

       News news = (News) session.get(News.class, 1);

       Blob image = news.getImage();

    }

通常是把文件传到一个指定文件夹下,然后在数据表中设置一个path(dir)字段,这个字段指向那个文件

 

映射组成关系,

建立域模型和关系数据模型有着不同的出发点

域模型:由程序代码组成,通过细化持久化类的粒度,可提高代码的可重用性,简化编程。

 

关系数据模型:在没有冗余的情况下,应该尽可能减少表的数目,简化表之间的参照关系,以便提高数据数据的访问速度。

因此,有时候我们看到两个Java类中对应的却是一张数据库表

 

Hibernate把持久化类的属性分为两种:

值(value)类型:没有OID,不能被单独持久化,生命周期依赖于所属的持久化类的对象的生命周期。

实体(entity)类型:有OID,可以被单独持久化,有独立的生命周期。

显然无法直接用property映射pay属性

Hibernate使用<component>元素来映射组成关系,该元素表名pay属性时Worker类的一个组成部分,在Hibernate中称之为组件

<component>元素来映射组成关系

Class:设定组成关系属性的类型,此处表明pay属性为pay类型

<paremt>元素指定组件属性所属的整体类

Name:整体类在组件类中的属性名

 

例如:

public class Worker {

    private Integer id;

    private String name;

    private Pay pay;

 

public class Pay {

    private int monthlyPay;

    private int yearPay;

    private int vocationWithPay;

 

<hibernate-mapping package="com.clou.entity" >

    <class name="Worker" table="worker" >

       <id name="id" type="java.lang.Integer">

           <column name="id"></column>

           <generator class="native"></generator>

       </id>

       <property name="name" type="string">

           <column name="name"></column>

       </property>

       <!-- 映射组成关系使用component -->

       <component name="pay" class="Pay"><!-- 因为package属性已经设置了 -->

           <!-- 指定组成关系的组件的属性 -->

           <property name="monthlyPay" column="monthly_pay"></property>

           <property name="yearPay" column="year_pay"></property>

           <property name="vocationWithPay" column="vocation_with_pay"></property>

       </component>

    </class>

</hibernate-mapping>

 

测试方法:

    @Test

    public void testComponent(){

       Worker worker = new Worker();

       Pay pay = new Pay();

      

       pay.setMonthlyPay(1000);

       pay.setYearPay(80000);

       pay.setVocationWithPay(5);

 

       worker.setName("ABCD");

       worker.setPay(pay);

       session.save(worker);

    }

 

 

测试2:

例如:

public class Worker {

    private Integer id;

    private String name;

    private Pay pay;

 

public class Pay {

    private Worker worker;

    private int monthlyPay;

    private int yearPay;

    private int vocationWithPay;

 

 

<hibernate-mapping package="com.clou.entity" >

    <class name="Worker" table="worker" >

       <id name="id" type="java.lang.Integer">

           <column name="id"></column>

           <generator class="native"></generator>

       </id>

       <property name="name" type="string">

           <column name="name"></column>

       </property>

       <!-- 映射组成关系使用component -->

       <component name="pay" class="Pay"><!-- 因为package属性已经设置了 -->

<parent name=”worker”/><!—这样效果跟上面是一样的 ,只是更进一步的指定了关系-->

           <!-- 指定组成关系的组件的属性 -->

           <property name="monthlyPay" column="monthly_pay"></property>

           <property name="yearPay" column="year_pay"></property>

           <property name="vocationWithPay" column="vocation_with_pay"></property>

       </component>

    </class>

</hibernate-mapping>

测试方法:

    @Test

    public void testComponent(){

       Worker worker = new Worker();

       Pay pay = new Pay();

      

       pay.setMonthlyPay(1000);

       pay.setYearPay(80000);

       pay.setVocationWithPay(5);

      

       worker.setName("ABCD");

       worker.setPay(pay);

      

       session.save(worker);

    }