Hibernate学习笔记 | 详解Hibernate的配置文件和映射文件

详解Hibernate配置文件

Hibernate配置文件概述

  • Hibernate配置文件主要用于配置数据库连接和Hibernate运行时所需的各种属性。
  • 每个Hibernate配置文件对应一个Configuration对象。
  • Hibernate配置文件可以有两种格式:
    hibernate.properties
    hibernate.cfg.xml

hibernate.cfg.xml的常用属性

  • JDBC连接属性
    connection.url:数据库URL
    connection.username:数据库用户名
    connection.password:数据库用户密码
    connection.driver_class:数据库JDBC驱动
    dialect:配置数据库的方言,根据底层的数据库不同产生不同的sql语句,Hibernate会针对数据库的特性在访问时进行优化
  • 其它
    show_sql:是否将运行期生成的SQL输出到日志以供调试,取值为truefalse
    format_sql:是否将sql转化为格式良好的sql,取值为truefalse
    hbm2ddl.auto:在启动或停止时自动地创建、更新或删除数据库模式。取值为create,update,create-drop,validate
    hibernate.jdbc.fetch_size:JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。
    hibernate.jdbc.batch_size:对数据库进行批量删除,更新,插入的时候批次的大小。
<!-- 设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数-->
<property name="hibernate.jdbc.fetch_size">100</property>
<!-- 设定对数据库进行批量删除,更新,插入的时候批次的大小 -->
<property name="hibernate.jdbc.batch_size">30</property>

Hibernate中使用C3P0数据源

步骤:

  • 导入jar包
    导入c3p0-0.9.2.1.jarmchange-commons-java-0.2.3.4.jarhibernate-c3p0-5.2.10.Final.jar等文件。
  • 加入配置
    首先要配置hibernate.connection.provider_class属性,然后再配置以下的属性:·
    c3p0.max_size:数据库连接池的最大连接数
    c3p0.min_size:数据库连接池的最小连接数
    c3p0.acquire_increment:当数据库连接池中的连接耗尽时,同一时刻获取多少个数据库连接
    c3p0.timeout:数据库连接池中连接对象在多场时间没有使用过后,就应该销毁
    c3p0.idle_test_period:表示连接池检测线程多少时间检测一次池内的所有链接对象是否超时
    连接池本身不会把自己从连接池中移除,
    c3p0.max_statements:缓存Statement对象的数量
    配置示例如下:
<!-- 配置C3P0数据源 -->
<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<property name="c3p0.max_size">10</property>
<property name="c3p0.min_size">5</property>
<property name="c3p0.acquire_increment">2</property>
<property name="c3p0.idle_test_period">2000</property>
<property name="c3p0.timeout">2000</property>
<property name="c3p0.max_statements">10</property>

详解Hibernate映射文件

POJO类和数据库的映射文件

  • POJO类和关系数据库之间的映射可以用一个XML文档来定义。
  • 通过POJO类的数据库映射文件,Hibernate可以理解持久化类和数据表之间的对应关系,也可以理解持久化类属性与数据库表列之间的对应关系。
  • 在运行时Hibernate将根据这个映射文件来生成各种SQL语句。
  • 映射文件的扩展名为.hbm.xml

class节点

<class>节点是<hibernate-mapping>的子节点,比较常用的属性如下:

class节点的常用属性

  • name:指定该持久化类映射的持久化类的类名
  • table:指定该持久化类映射的表明,Hibernate默认以持久化类的类名作为表名
  • select-before-update:设置Hibernate在更新某个持久化对象之前是否需要先执行一次查询,默认值为false
  • dynamic-insert:若设置为true,表示当保存一个对象时,会动态生成insert语句,insert语句中仅包含所有取值不为null的字段,默认值为false
  • dynamic-update:若设置为true,表示当更新一个对象时,会动态生成update语句,update语句中仅包含所有取值需要更新的字段,默认值为false

映射对象标识符

  • Hibernate使用对象标识符(OID)来建立内存中的对象和数据库表中记录的对应关系。对象的OID和数据表的主键对应,Hibernate通过标识符生成器来为主键赋值。
  • Hibernate推荐在数据表中使用代理主键,即不具备业务含义的字段,代理主键通常为整数类型,因为整数类型比字符串类型要节省更多的数据库空间。
  • 在对象-关系映射文件中,<id>元素用来设置对象标识符,<generator>子元素用来设定标识符生成器。
  • Hibernate提供了标识符生成器接口:IdentifierGenerator,并提供了各种内置实现。

id节点

<id>节点用来设定持久化类的OID和表的主键的映射

  • name:标识持久化类OID的属性名
  • column:设置表示属性所映射的数据表的列名(主键字段的名字)
  • unsaved-value:若设定了该属性,Hibernate会通过比较持久化类的OID值和该属性值来区分当前持久化类的对象是否为临时对象

Hibernate的内置标识符生成器

  • increment标识符生成器由Hibernate以递增的方式为代理主键赋值
    Hibernate会先读取数据表中的主键的最大值,而接下来向数据表插入记录时,就在max(id)的基础上递增,增量为1。但是会产生并发问题,因此不适合。

  • indentity标识符生成器由底层数据库来负责生成标识符,它要求底层数据库把主键定义为自动增长字段类型。
    MySQL支持,而Oracle不支持。
    OID必须为long,int,short类型,如果把OID定义为byte类型,在运行时会抛出异常。

  • sequence标识符生成器利用底层数据库提供的序列来生成标识符。
    Hibernate在持久化一个对象时,先从底层数据库的序列中获得一个唯一的标识号,再把它作为主键值。
    需要底层数据库系统支持序列,支持序列的数据库包括:DB2,Oracle等。
    OID必须为long,int,short类型,如果把OID定义为byte类型,在运行时会抛出异常。

  • hilo标识符生成器由Hibernate按照一种high/low算法生成标识符,它从数据库的特定表的字段中获取high值。
    Hibernate在持久化一个对象时,由Hibernate负责生成主键值,hilo标识符生成器在生成标识符时,需要读取并修改对应表中的NEXT_VALUE值。
    该生成器适用于所有的数据库系统。
    OID必须为long,int,short类型,如果把OID定义为byte类型,在运行时会抛出异常。

  • native标识符生成器依据底层数据库对自动生成标识符的支持能力,来选择使用identity,sequence或hilo标识符生成器。
    该标识符生成器适合跨数据库平台开发,OID必须为long,int,short类型,如果把OID定义为byte类型,在运行时会抛出异常。

<id name="id" column="id">
     <generator class="native" />
</id>

property节点

  • name:指定该持久化类的属性的名字
  • column:指定与类的属性映射的表的字段名,如果没有设置该属性,Hibernate将直接使用类的属性名作为字段名。
  • type:指定Hibernate映射类型,Hibernate映射类型是Java类型与SQL类型的桥梁,如果没有为某个属性显式设定映射类型。Hibernate会运用反射机制先识别出持久化类的特定属性的Java类型,然后自动使用与之对应的默认的Hibernate映射类型。
  • not-null:若该属性值为true,表示不允许为null,默认为false
  • access:指定Hibernate的默认的属性访问策略,默认值为property,即使用getter,setter方法来访问属性,若指定field,则Hibernate会忽略getter/setter方法,而通过反射访问成员变量。
  • unique:设置是否为该属性所映射的数据列添加唯一的束。
  • index:指定一个字符串的索引名称,当系统需要Hibernate自动建表时,用于为该属性所映射的数据列创建索引,从而加快该数据列的查询。
  • length:指定该属性所映射数据列的字段的长度。
  • scale:指定该属性所映射数据列的小数位数,对double,float,decimal等类型的数据列有效。
  • formula:设置一个SQL表达式,Hibernate将根据它来计算出派生属性的值。
    派生属性:并不是持久化来的所有属性都直接和表的字段匹配,持久化类的有些属性的值必须在运行时通过计算才能得出来,这种属性称为派生属性。
    使用formula属性时,formula="(sql)"的英文括号不能少,且Sql表达式中的列名和表名都应该和数据库对应,而不是和持久化对象的属性对应。如果需要在formula属性中使用参数,就使用例如where cus.id=id的形式,其中id就是参数,和当前持久化对象的id属性对应的列的id值将作为参数传入。

一个示例:使用formula属性
首先在类中新增一个属性为desc,并设置对应的getter和setter方法,该属性等于author+":"+title。新增属性后的类如下:

package com.cerr.hibernate.helloworld;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.Date;
import java.util.Objects;

@Entity
public class News {
    private int id;
    private String title;
    private String author;
    private Date date;

    //该属性值为author:title
    private String desc;
    public News() {
    }

    @Id
    @Column(name = "id")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Basic
    @Column(name = "title")
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Basic
    @Column(name = "author")
    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Basic
    @Column(name = "date")
    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        News news = (News) o;
        return id == news.id &&
                Objects.equals(title, news.title) &&
                Objects.equals(author, news.author) &&
                Objects.equals(date, news.date);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, title, author, date);
    }

    public News(String title, String author, Date date) {
        this.title = title;
        this.author = author;
        this.date = date;
    }

    @Override
    public String toString() {
        return "News{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", date=" + date +
                '}';
    }
}

然后在映射文件中新增配置:<property name="desc" formula="(SELECT concat(author,':',title) FROM news n WHERE n.id = id)"/>
测试类部分代码如下(能打印出desc):

@Test
public void test2(){
   News news = session.get(News.class,1);
   news.setAuthor("ab");
   System.out.println(news.getDesc());
}

Java时间和日期类型的Hibernate映射

  • 在Java中,代表时间和日期的类型包括java.util.Datejava.util.Calendar,此外,在JDBC API中还提供了3个扩展了java.util.Date类的子类:java.sql.Datejava.sql.Timejava.sql.Timestamp,这三个类分别和标准SQL类型中的DATETIMETIMESTAMP类型对应。在标准SQL中,DATE类型表示日期,TIME类型表示时间,TIMESTAMP类型表示时间戳,同时包含日期和时间信息

  • 因为java.util.Datejava.sql.Datejava.sql.Timejava.sql.Timestamp三个类的父类,所以java.util.Date可以对应标准SQL中的DATETIMETIMESTAMP类型。所以在设置持久化类的Date类型时设置为java.util.Date

  • 可以通过property的type属性来把java.util.Date属性映射为DATETIMETIMESTAMP类型。
    例如<property name="date" column="date" type="timestamp"/>,其中timestamp既不是java类型,也不是标准的sql类型,而是Hibernate映射类型。

映射组成关系

  • Hibernate把持久化类的属性分为两种:
    值类型:没有OID,不能被单独持久化,生命周期依赖于所属的持久化类的对象的生命周期。
    实体类型:有OID,可以被单独持久化,有独立的生命周期。

  • Hibernate使用<component>元素来映射组成关系,该元素表明xx属性是某实体类的一个组成部分,在Hibernate中称之为组件。

一个Demo:
首先我们先创建两个实体类,代码如下(省略了getter和setter方法):
Worker类:

package com.cerr.hibernate.helloworld;

public class Worker {
    private Integer id;
    private String name;
    private Pay pay;
}

Pay类(属于Worker的一个组件):

package com.cerr.hibernate.helloworld;

public class Pay {
    private int monthlyPay;
    private int yearPay;
    private int vocationWithPay;
}

Hibernate映射文件(Worker.hbm.xml):

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!--加入select-before-update="true" -->
    <class name="com.cerr.hibernate.helloworld.Worker" table="worker" schema="hibernate5" >
        <id name="id" column="id">
            <generator class="native" />
        </id>
        <property name="name" column="title"/>
        <!-- 映射组成关系 -->
        <component name="pay" class="com.cerr.hibernate.helloworld.Pay">
            <!-- 指定组成关系的组件的属性 -->
            <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 test3(){
    Worker worker = new Worker();
    Pay pay = new Pay();
    pay.setMonthlyPay(1000);
    pay.setYearPay(800);
    pay.setVocationWithPay(111);
    worker.setName("aaa");
    worker.setPay(pay);
    session.save(worker);
}

按理说该测试类会成功运行,但是此时却报错了。后来发现是因为在Hibernate的配置文件中数据库方言使用了一个已过时的API,后来换了一个比较新的之后就成功通过了。换用的数据库方言为:<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
查看数据库会发现只有一张worker的数据表,而pay的属性附加在该表中,表的信息如下:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容