详解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输出到日志以供调试,取值为true
或false
。
format_sql
:是否将sql转化为格式良好的sql,取值为true
或false
。
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.jar
和mchange-commons-java-0.2.3.4.jar
和hibernate-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>
的子节点,比较常用的属性如下:
-
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.Date
和java.util.Calendar
,此外,在JDBC API中还提供了3个扩展了java.util.Date
类的子类:java.sql.Date
,java.sql.Time
和java.sql.Timestamp
,这三个类分别和标准SQL类型中的DATE
,TIME
和TIMESTAMP
类型对应。在标准SQL中,DATE
类型表示日期,TIME
类型表示时间,TIMESTAMP
类型表示时间戳,同时包含日期和时间信息因为
java.util.Date
是java.sql.Date
,java.sql.Time
和java.sql.Timestamp
三个类的父类,所以java.util.Date可以对应标准SQL中的DATE
,TIME
,TIMESTAMP
类型。所以在设置持久化类的Date类型时设置为java.util.Date
。可以通过property的type属性来把
java.util.Date
属性映射为DATE
,TIME
,TIMESTAMP
类型。
例如<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的属性附加在该表中,表的信息如下: