hibernate.cfg.xml配置文件
- Hibernate 配置文件主要用于配置数据库连接和 Hibernate 运行时所需的各种属性
- 每个 Hibernate 配置文件对应一个 Configuration 对象
- Hibernate配置文件可以有两种格式:
- hibernate.properties
- hibernate.cfg.xml
推荐使用第二种方式
- JDBC 连接属性
- connection.url:数据库URL
- connection.username:数据库用户名
- connection.password:数据库用户密码
- connection.driver_class:数据库JDBC驱动
- dialect:配置数据库的方言,根据底层的数据库不同产生不同的 sql 语句,Hibernate 会针对数据库的特性在访问时进行优化
- c3p0数据源
c3p0 用于控制数据库的链接数量
C3P0 数据库连接池属性
- hibernate.c3p0.max_size: 数据库连接池的最大连接数
- hibernate.c3p0.min_size: 数据库连接池的最小连接数
- hibernate.c3p0.timeout: 数据库连接池中连接对象在多长时间没有使用过后,就应> 该被销毁
- hibernate.c3p0.max_statements: 缓存 Statement 对象的数量
- hibernate.c3p0.idle_test_period: 表示连接池检测线程多长时间检测一次池内的> 所 有链接对象是否超时. 连接池本身不会把自己从连接池中移除,而是专门有一 个线 程按照一定的时间间隔来做这件事,这个线程通过比较连接对象最后一次被使用时间和当前时间的时间差来和 timeout 做对比,进而决定是否销毁这个连接对象。
hibernate.c3p0.acquire_increment: 当数据库连接池中的连接耗尽时, 同一时刻获取> 多少个数据库连接
<!--设置连接池最大连接数-->
<property name="c3p0.max_size">30</property>
<!--设置连接池最小连接数-->
<property name="c3p0.min_size">10</property>
<!--当连接对象多长时间没有使用就会被销毁-->
<property name="c3p0.timeout">50000</property>
<!--缓存 Statement 对象的数量-->
<property name="c3p0.max_statements">10</property>
<!--连接池检测线程多长时间检测一次池内的所有链接对象是否超时-->
<property name="c3p0.idle_test_period">100000</property>
<!--当数据库连接池中的连接耗尽时, 同一时刻获取多少个数据库连接-->
<property name="c3p0.acquire_increment">5</property>
- jdbc.fetch_size
hibernate.jdbc.fetch_size:实质是调用 Statement.setFetchSize() 方法设定 JDBC 的 Statement 读取数据的时候每次从数据库中取出的记录条数。
- 例如一次查询1万条记录,对于Oracle的JDBC驱动来说,是不会 1 次性把1万条取出来的,而只会取出 fetchSize 条数,当结果集遍历完了这些记录以后,再去数据库取 fetchSize 条数据。因此大大节省了无谓的内存消耗。Fetch Size设的越大,读数据库的次数越少,速度越快;Fetch Size越小,读数据库的次数越多,速度越慢。Oracle数据库的JDBC驱动默认的Fetch Size = 10,是一个保守的设定,根据测试,当Fetch Size=50时,性能会提升1倍之多,当 fetchSize=100,性能还能继续提升20%,Fetch Size继续增大,性能提升的就不显著了。并不是所有的数据库都支持Fetch Size特性,例如MySQL就不支持
<!--设置每次从数据库中读取的记录数量-->
<property name="default_batch_fetch_size">100</property>
- jdbc.batch_size
hibernate.jdbc.batch_size:设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,类似于设置缓冲区大小的意思。batchSize 越大,批量操作时向数据库发送sql的次数越少,速度就越快。
- 测试结果是当Batch Size=0的时候,使用Hibernate对Oracle数据库删除1万条记录需要25秒,Batch Size = 50的时候,删除仅仅需要5秒!Oracle数据库 batchSize=30 的时候比较合适。
<!--设置每次执行批处理的sql语句数量-->
<property name="jdbc.batch_size">10</property>
对象关系映射文件
- POJO 类和关系数据库之间的映射可以用一个XML文档来定义。
- 通过 POJO 类的数据库映射文件,Hibernate可以理解持久化类和数据表之间的对> 应关系,也可以理解持久化类属性与数据库表列之间的对应关系
- 在运行时 Hibernate 将根据这个映射文件来生成各种 SQL 语句
- 映射文件的扩展名为 .hbm.xml
-
每个Hibernate-mapping中可以同时定义多个类. 但更推荐为每个类都创建一个单独的映射文件
-
映射文件说明
- hibernate-mapping
- 类层次: class
- 主键:id
- 基本类型:property
- 实体引用类: many-to-one |one-to-one
- 集合:set | list | map | array
- one-to-many
- many-to-many
- 子类:subclass | joined-subclass
- 其它:component | any 等
- 查询语句:query(用来放置查询语句,便于对数据库查询的统一管理和优化)
- hibernate-mapping节点
<hibernate-mapping package="mao.shu.vo" >
</hibernate-mapping>
- class节点
<!--设置映射的java类,name为类的名称,table为对应数据库之中的表名称,dynamic-update表示是否动态生成update语句-->
<class name="News" table="NEWS" dynamic-update="true">
</class>
- 当设置了动态生成update语句之后,如果在程序之中使用了update()方法
@Test
public void testDynamicUpdate(){
News vo = (News)this.session.get(News.class,4);
vo.setInfo("testDynamicUpdate");
this.session.update(vo);
}
-
使用动态生成update语句,只会更新对象被修改的属性,
-
映射对象标识符
-
Hibernate 使用对象标识符(OID) 来建立内存中的对象和数据库表中记录的对应关系. 对象的 OID 和数据表的主键对应. Hibernate 通过标识符生成器来为主键赋值
-
Hibernate 推荐在数据表中使用代理主键, 即不具备业务含义的字段. 代理主键通常为整数类型, 因为整数类型比字符串类型要节省更多的数据库空间.
-
在对象-关系映射文件中, 元素用来设置对象标识符. 子元素用来设定标识符生成器.
-
Hibernate 提供了标识符生成器接口: IdentifierGenerator, 并提供了各种内置实现
<!--设置对象主键
name对应的就是java类中的属性
column对应的是数据表中的数据列名称
type对应的是该字段的数据类型
-->
<id name="id" column="ID" type="java.lang.Integer">
<generator class="native"/>
</id>
- 主键生成策略generator
标识符生成器 | 描述 |
---|---|
increment | 适合于代理主键,有Hibernate自增生成 (每次增加时都需要查询一次,如果出现高并发的情况,可能导致id重复) |
identity | 由底层数据库生成的标识符 |
sequence | 如果使用的数据库支持序列操作例如:Oracle数据库,则可以使用该生成方式 |
hilo | hibernate分局height/low算法生成标识符 |
seqhilo | 使用高低算法高效的生成long, short,或int类型的标识符,比hilo生成器据更好的性能 |
native | 自动选择identity或hilo或sequence中的一个生成标识符推荐使用该方式 |
uuid.hex | 采用128为的UUID算法生成标识符 |
uuid.string | 生成一个16位字符串的UUID标识符 |
assigned | 有java程序负责生成标识符 |
foreign | 使用另外一个关联对象的的标识符 |
<id name="id" column="ID" type="java.lang.Integer">
<generator class="hilo"/>
</id>
- 使用hilo表示符生成器时,程序中使用save()方法插入一条数据,得到的id值
@Test
public void testHilo(){
News vo = new News();
vo.setInfo("testHilo测试");
vo.setTitle("testHilo");
vo.setPrice(20.0);
vo.setPubDate(new Date());
this.session.save(vo);
}
- hibernate所执行的sql
- 数据表中生成的数据
- prooerty节点
@Test
public void testFormula(){
News vo = (News)this.session.get(News.class,4);
//取得派生属性
System.out.println(vo.getDesc());
}
映射文件2—java类型与映射类型
-
Java中的时间类型
-
java中代表时间的类型有
- java.util.Date
- java.util.Calendar
-
在JDBC开发包之中扩展的日期类型有
- java.sql.Date
- java.sql.Time
- java.sql.Timestamp
-
其中java.util.Date代表的是日期时间,就是"yyyy-MM-dd HH:mm:ss",而java.sql.Date没有时间部分,“yyyy-MM-dd”
-
如何进行映射?
-
java.util.Date是java.sql.Date,与java.sqlTime和java.sql.Timestamp的父类,所以java.util.Date可以对应标准的sql类型中的DATE,TIME和TIMESTAMP
-
所以在设置持久化类的Date类型,最好设置为java.util.Date类型
/*设置日期映射*/
private Date pubDate;
- 如何将java.util.Date类型映射为:DATE,TIME或TMESTAMP
- 可以通过property节点中的type属性进行映射
<!--将java.util.Date 类型映射为 TIME类型-->
<property name="pubDate" type="time" column="PUBDATE"/>
<!--将java.util.Date 类型映射为 TIMESTAMP类型-->
<property name="pubDate" type="timestamp" column="PUBDATE"/>
<!--将java.util.Date 类型映射为 DATE类型-->
<property name="pubDate" type="date" column="PUBDATE"/>
- 其中timestamp,date,time既不是java类型,也不是标准sql类型,而是hibernate映射类型.
- Java 类型, Hibernate 映射类型及 SQL 类型之间的对应关系
- java大对象类型的映射
在 Java 中, java.lang.String 可用于表示长字符串(长度超过 255), 字节数组 byte[] 可用于存放图片或文件的二进制数据. 此外, 在 JDBC API 中还提供了 java.sql.Clob 和 java.sql.Blob 类型, 它们分别和标准 SQL 中的 CLOB 和 BLOB 类型对应. CLOB 表示字符串大对象(Character Large Object), BLOB表示二进制对象(Binary Large Object)
Mysql 不支持标准 SQL 的 CLOB 类型, 在 Mysql 中, 用 TEXT, MEDIUMTEXT 及 LONGTEXT 类型来表示长度操作 255 的长文本数据
- 在持久化类中, 二进制大对象可以声明为 byte[] 或 java.sql.Blob 类型; 字符串可以声明为 java.lang.String 或 java.sql.Clob
- 实际上在 Java 应用程序中处理长度超过 255 的字符串, 使用 java.lang.String 比 java.sql.Clob 更方便
- 示例:在News类中添加一个Clob类型和一个Blob类型的属性
private Blob image;//保存图片
private Clob content;//保存文本
//getter和setter方法
- 在News.hbm.xml文件中设置映射关系
<!--设置图片的映射关系-->
<property name="image" type="blob" column="IMAGE"/>
<!--设置文本的映射关系-->
<property name="content" type="clob" column="CONTENT"/>
-
在实际开发中很少会直接在数据库中直接存一个图片的文件,而是会将这个图片文件存储在一个文件夹中,然后在数据库之中设置一个"PATH"字段保存图片所在的路径
-
保存图片的时候使用InputStream类进行保存
@Test
public void testBlob()throws Exception{
News vo = new News();
vo.setPubDate(new Date());
vo.setPrice(500.5);
vo.setTitle("保存图片");
vo.setInfo("测试");
/*保存文本*/
vo.setContent(Hibernate.getLobCreator(this.session).createClob("你好"));
//使用InputStream描述一个图片文件
InputStream imgInput = new FileInputStream("timg.jpg");
//使用Hibernate的一个工具类创建一个Blog 对象
Blob img = Hibernate.getLobCreator(this.session).createBlob(imgInput,imgInput.available());
vo.setImage(img);
this.session.save(vo);
}
- 保存的数据
- 测试读取图片
@Test
public void getBlob()throws Exception{
News vo = (News) this.session.get(News.class,65536);
Blob img = vo.getImage();
System.out.println("图片大小为:"+img.length());
}
- 映射组成关系
建立域模型和关系数据模型有着不同的出发点:
- 域模型: 由程序代码组成, 通过细化持久化类的的粒度可提高代码的可重用性, 简化编程
- 在没有数据冗余的情况下, 应该尽可能减少表的数目, 简化表之间的参照关系, 以便提高数据的访问速度
- Hibernate 把持久化类的属性分为两种:
- 值(value)类型: 没有 OID, 不能被单独持久化, 生命周期依赖于所属的持久化类的对象的生命周期
- 实体(entity)类型: 有 OID, 可以被单独持久化, 有独立的生命周期
Hibernate 使用 <component> 元素来映射组成关系, 该元素表名 pay 属性是 Worker 类一个组成部分, 在 Hibernate 中称之为组件
- 示例:编写一个Work持久化程序类
public class Work {
private Integer id;
private String name;
private Integer age;
private Pay sal;
//getter 和setter方法
//toString方法
}
- 编写 Pay程序类
public class Pay {
private Integer monthPay;
private Integer yearPay;
private Integer vacationWithPay;
private Work work;
//getter和setter方法
//toString方法
}
-
这两个类描述的其实是数据表中的一张表的内容,只不过将一张表中的内容分为两个java类描述
-
编写 Work.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--定义对象关系映射,package设置类所在的包名称-->
<hibernate-mapping package="mao.shu.vo" >
<class name="Work">
<id name="id" type="java.lang.Integer" >
<generator class="native"/>
</id>
<property name="name" type="java.lang.String"/>
<property name="age" type="java.lang.Integer"/>
<!--映射组成关系-->
<component name="sal" class="Pay">
<!--指定组件属性所属的整体类-->
<parent name="Work"/>
<!--描述关联类的属性映射-->
<property name="monthPay" type="java.lang.Integer"/>
<property name="yearPay" type="java.lang.Integer"/>
<property name="vacationWithPay" type="java.lang.Integer"/>
</component>
</class>
</hibernate-mapping>
- 在使用<parent>组件描述所属的整体类的时候,要确保组件(Pay类)中拥有一个Work类的类成员,否者解析这个配置文件的时候将会出现错误
private Work work;
- 在hibernate.cfg.xml文件中配置映射文件
<mapping resource="mao/shu/vo/Work.hbm.xml"/>
- 测试保存一条Work数据
@Test
public void getWork()throws Exception{
Work work = new Work();
work.setName("xiemaoshu");
work.setAge(12);
Pay pay = new Pay();
pay.setMonthPay(5000);
pay.setYearPay(5000000);
pay.setVacationWithPay(200);
work.setSal(pay);
this.session.save(work);
}
- 添加的数据