詳解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的屬性附加在該表中,表的信息如下: