正式進入Hibernate
Hibernate 架構
Hibernate 架構是分層的,作為資料訪問層,你不必知道底層 API 。Hibernate 利用資料庫以及配置資料來為應用程式提供持續性服務(以及持續性物件)。
下面是一個非常高水平的 Hibernate 應用程式架構檢視。
下面是一個詳細的 Hibernate 應用程式體系結構檢視以及一些重要的類。
Hibernate 使用不同的現存 Java API,比如 JDBC,Java 事務 API(JTA),以及 Java 命名和目錄介面(JNDI)。JDBC 提供了一個基本的抽象級別的通用關係資料庫的功能, Hibernate 支援幾乎所有帶有 JDBC 驅動的資料庫。JNDI 和 JTA 允許 Hibernate 與 J2EE 應用程式伺服器相整合。
下面的部分簡要地描述了在 Hibernate 應用程式架構所涉及的每一個類物件。
配置物件:
配置物件是你在任何 Hibernate 應用程式中創造的第一個 Hibernate 物件,並且經常只在應用程式初始化期間創造。它代表了 Hibernate 所需一個配置或屬性檔案。配置物件提供了兩種基礎元件。
- 資料庫連線:由 Hibernate 支援的一個或多個配置檔案處理。這些檔案是 hibernate.properties 和 hibernate.cfg.xml。
- 類對映設定:這個元件創造了 Java 類和資料庫表格之間的聯絡。
SessionFactory 物件
- 配置物件被用於創造一個 SessionFactory 物件,使用提供的配置檔案為應用程式依次配置 Hibernate,並允許例項化一個會話物件。SessionFactory 是一個執行緒安全物件並由應用程式所有的執行緒所使用。
- SessionFactory 是一個重量級物件所以通常它都是在應用程式啟動時創造然後留存為以後使用。每個資料庫需要一個 SessionFactory 物件使用一個單獨的配置檔案。所以如果你使用多種資料庫那麼你要創造多種 SessionFactory 物件。
Session 物件
- 一個會話被用於與資料庫的物理連線。Session 物件是輕量級的,並被設計為每次例項化都需要與資料庫的互動。持久物件通過 Session 物件儲存和檢索。
- Session 物件不應該長時間保持開啟狀態因為它們通常情況下並非執行緒安全,並且它們應該按照所需創造和銷燬。
Transaction 物件
- 一個事務代表了與資料庫工作的一個單元並且大部分 RDBMS 支援事務功能。在 Hibernate 中事務由底層事務管理器和事務(來自 JDBC 或者 JTA)處理。
- 這是一個選擇性物件,Hibernate 應用程式可能不選擇使用這個介面,而是在自己應用程式程式碼中管理事務。
Query 物件
- Query 物件使用 SQL 或者 Hibernate 查詢語言(HQL)字串在資料庫中來檢索資料並創造物件。一個查詢的例項被用於連結查詢引數,限制由查詢返回的結果數量,並最終執行查詢。
Criteria 物件
- Criteria 物件被用於創造和執行面向規則查詢的物件來檢索物件。
Hibernate(自帶Jar包除外的)一些常用 Jar 包介紹
Jar 包 / 類庫 | 解釋 |
---|---|
dom4j | XML 解析 www.dom4j.org/ |
Xalan | XSLT 處理器 http://xml.apache.org/xalan-j/ |
Xerces | The Xerces Java 解析器 http://xml.apache.org/xerces-j/ |
cglib | Java 類生成庫http://cglib.sourceforge.net/ |
log4j | 日誌控制 http://logging.apache.org/log4j |
Commons | 日誌,郵件等 http://jakarta.apache.org/commons |
SLF4J | 簡單日誌門面 http://www.slf4j.org |
Hibernate 配置
Hibernate 需要事先知道在哪裡找到對映資訊,這些對映資訊定義了 Java 類怎樣關聯到資料庫表。Hibernate 也需要一套相關資料庫和其它相關引數的配置設定。所有這些資訊通常是作為一個標準的 Java 屬性檔案提供的,名叫 hibernate.properties。又或者是作為 XML 檔案提供的,名叫 hibernate.cfg.xml。
我們將考慮 hibernate.cfg.xml 這個 XML 格式檔案,來決定在我的例子裡指定需要的 Hibernate 應用屬性。這個 XML 檔案中大多數的屬性是不需要修改的。這個檔案儲存在應用程式的類路徑的根目錄裡。
Hibernate 屬性
下面是一個重要的屬性列表,你可能需要表中的屬性來在單獨的情況下配置資料庫。
屬性 | 描述 |
---|---|
hibernate.dialect | 這個屬性使 Hibernate 應用為被選擇的資料庫生成適當的 SQL。 |
hibernate.connection.driver_class | JDBC 驅動程式類。 |
hibernate.connection.url | 資料庫例項的 JDBC URL。 |
hibernate.connection.username | 資料庫使用者名稱。 |
hibernate.connection.password | 資料庫密碼。 |
hibernate.connection.pool_size | 限制在 Hibernate 應用資料庫連線池中連線的數量。 |
hibernate.connection.autocommit | 允許在 JDBC 連線中使用自動提交模式。 |
如果您正在使用 JNDI 和資料庫應用程式伺服器然後您必須配置以下屬性
屬性 | 描述 |
---|---|
hibernate.connection.datasource | 在應用程式伺服器環境中您正在使用的應用程式 JNDI 名。 |
hibernate.jndi.class | JNDI 的 InitialContext 類。 |
hibernate.jndi. | 在 JNDI的 InitialContext 類中通過任何你想要的 Java 命名和目錄介面屬性。 |
hibernate.jndi.url | 為 JNDI 提供 URL。 |
hibernate.connection.username | 資料庫使用者名稱。 |
hibernate.connection.password | 資料庫密碼。 |
Hibernate 和 MySQL 資料庫
MySQL 資料庫是目前可用的開源資料庫系統中最受歡迎的資料庫之一。我們要建立 hibernate.cfg.xml 配置檔案並將其放置在應用程式的 CLASSPATH 的根目錄裡。你要確保在你的 MySQL 資料庫中 testdb 資料庫是可用的,而且你要有一個使用者 test 可用來訪問資料庫。
XML 配置檔案一定要遵守 Hibernate 3 Configuration DTD,在 http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd. 這個網址中是可以找到的。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- Assume test is the database name -->
<property name="hibernate.connection.url">
jdbc:mysql://localhost/test
</property>
<property name="hibernate.connection.username">
root
</property>
<property name="hibernate.connection.password">
root123
</property>
<!-- List of XML mapping files -->
<mapping resource="Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
上面的配置檔案包含與 hibernate-mapping 檔案相關的 標籤,我們將在下章看看 hibernate mapping 檔案到底是什麼並且要知道為什麼用它,怎樣用它。以下是各種重要資料庫同源語屬性型別的列表:
資料庫 | 方言屬性 |
---|---|
DB2 | org.hibernate.dialect.DB2Dialect |
HSQLDB | org.hibernate.dialect.HSQLDialect |
HypersonicSQL | org.hibernate.dialect.HSQLDialect |
Informix | org.hibernate.dialect. InformixDialect |
Ingres | org.hibernate.dialect. IngresDialect |
Interbase | org.hibernate.dialect. InterbaseDialect |
Microsoft SQL Server 2000 | org.hibernate.dialect. SQLServerDialect |
Microsoft SQL Server 2005 | org.hibernate.dialect. SQLServer2005Dialect |
Microsoft SQL Server 2008 | org.hibernate.dialect. SQLServer2008Dialect |
MySQL | org.hibernate.dialect. MySQLDialect |
Oracle (any version) | org.hibernate.dialect. OracleDialect |
Oracle 11g | org.hibernate.dialect. Oracle10gDialect |
Oracle 10g | org.hibernate.dialect. Oracle10gDialect |
Oracle 9i | org.hibernate.dialect. Oracle9iDialect |
PostgreSQL | org.hibernate.dialect. PostgreSQLDialect |
Progress | org.hibernate.dialect. ProgressDialect |
SAP DB | org.hibernate.dialect. SAPDBDialect |
Sybase | org.hibernate.dialect. SybaseDialect |
Sybase Anywhere | org.hibernate.dialect. SybaseAnywhereDialec |
物件持久化
什麼是物件持久化
所謂持久化(Persistence),即把資料(如記憶體中的物件)儲存到持久化裝置,即可永
久儲存的儲存裝置中(如磁碟)。
持久化的主要應用是將記憶體中的資料儲存到關係型的資料庫中,當然也可以儲存在磁碟
檔案中、XML 資料檔案中等。
為什麼要持久化
(1)記憶體不能持久;
(2)記憶體容量有限(記憶體是用於存放計算資料的);
(3)業務資料共享的需要(需要公共的持久裝置);
(4)為了使用大規模的檢索(所以要將資料改為適合大規模檢索的格式);
(5)資料管理的需要(安全、備份)
怎樣實現持久化
-
物件序列化
即實現了 Serializable 介面的類。適合於少量的物件進行暫時的持久化,適合於在網路上傳輸物件。但不符合企業級應用的需要。因為企業應用中對資料的要求是大量的、長時間儲存的、需要進行大規模查詢。
-
JDBC
優點:功能完備、從理論上說效率是最高的;可以儲存海量的資料並且適合進行大規模檢索;
缺點:開發效率和維護效率低;開發難度大,程式碼量大,佔到到總程式碼量的 1/3,或 1/2;
第一個 Hibernate 應用程式
一個POJO類:
public class Student {
private int sid;
private String sname;
private int age;
private double score;
public Student() {
}
Set/get方法省略
核心配置檔案:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- DB四要素 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">1234</property>
<property name="hibernate.connection.url">jdbc:mysql:///bwie</property>
<property name="hibernate.connection.username">root</property>
<!--方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!--生成sql-->
<property name="hibernate.hbm2ddl.auto">create</property>
<!--展示sql -->
<property name="hibernate.show_sql">true</property>
<!--格式化sql -->
<property name="hibernate.format_sql">true</property>
<!-- sesssion上下文 -->
<property name="hibernate.current_session_context_class">thread</property>
<!--關聯 對映檔案 -->
<mapping resource="com/bwie/bean/Student.hbm.xml"/>
</session-factory>
</hibernate-configuration>
它們的功能分別為:
-
create:每次載入主配置檔案時都會刪除上一次的生成的表,然後再生成新表,哪怕兩
次表結構沒有任何變化。
-
create-drop:每次載入主配置檔案時會生成表,但是 sessionFactory 一旦關閉,表就自
動刪除。
-
update:當表字段增加時,會新增欄位;當表字段減少時,不會減少欄位。若表結構沒
變化,但資料變化時,會修改資料
對映配置檔案程式碼:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-11-14 9:01:34 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.bwie.bean.Student" table="t_student">
<id name="sid">
<column name="sid"/>
<generator class="native" />
</id>
<property name="sname" type="java.lang.String">
<column name="SNAME" />
</property>
<property name="age" type="int">
<column name="AGE" />
</property>
<property name="score" type="double">
<column name="SCORE" />
</property>
</class>
</hibernate-mapping>
- <class/> 標籤該標籤用於設定 PO 類與資料表間的對映關係。
- name 屬性:指定持久化類。若<hibernate-mapping/>標籤設定了 package 屬性,那麼,此處的 name 屬性只需是類名即可;否則,需要是含包名的完整類名。
- table 屬性:指定與持久化類對應的資料表的名稱。若不指定,Hibernate 將預設為表名與類名相同
- catalog 屬性:指定資料庫。預設為主配置檔案中指定的 DB。
- <id/> 與<property/> 標籤它們都是<class/>標籤的子標籤。用於指定 PO 類的 id 屬性與表的主健間的對映關係。它們的屬性基本相同。常用的有, name 屬性:指定持久化類的屬性名
- column 屬性:指定資料表中與 name 屬性對應的欄位名。若不指定,預設為與 name 屬性同名。
- length 屬性:指定屬性所對映欄位的長度,單位位元組。
- not-null 屬性:為指定欄位新增非空約束。
- unique 屬性:為指定欄位新增唯一性約束。
- type 屬性:指定屬性所對映的欄位的型別。若省略 Hibernate 會自動從持久化類中檢測到型別。這裡的型別取值支援兩類:Java 型別與 Hibernate 型別。
- Java 型別指的是 Java 程式碼中的型別。若是基本資料型別,如 int、double 等,直接寫即可。但若是物件型別,則需要寫上全類名,如 java.lang.String。
測試新增一條資料:
public class TestMain {
public static void main(String[] args) {
// 讀取核心配置檔案
Configuration cfg = new Configuration().configure();
// 構建核心SessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 獲取session
Session session = sessionFactory.openSession();
// 開啟事務
Transaction transaction = session.beginTransaction();
// 新增物件
Student s1 = new Student();
s1.setSname("Admin");
s1.setScore(98.0);
s1.setAge(18);
s1.setSid(10);
session.save(s1);
// 提交事務
transaction.commit();
}
}
單元測試Junit測試效果:
public class MyTest {
@Test
public void test() {
//讀取核心配置檔案
Configuration cfg=new Configuration().configure();
//構建核心SessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
//獲取session
Session session = sessionFactory.openSession();
//開啟事務
session.beginTransaction();
//新增物件
Student s1=new Student();
s1.setSname("Peter");
s1.setScore(98.0);
s1.setAge(18);
session.save(s1);
//提交事務
session.getTransaction().commit();
}
}
構建查詢列表語句:
@Test
public void test01() {
//讀取核心配置檔案
Configuration cfg=new Configuration().configure();
//構建核心SessionFactory
SessionFactory sessionFactory = cfg.buildSessionFactory();
//獲取session
Session session = sessionFactory.openSession();
//構建hql語句
String hql="from Student";
//查詢
List<Student> list = session.createQuery(hql).list();
//展示一下情況
for (Student student : list) {
System.out.println(student);
}
}
查詢的效果如下:
Hibernate 常用的內建主鍵生成策略:
主鍵生成策略,即主鍵的生成方式。不同的生成策略,其生成主鍵的方法與值不同。注意,以下在測試時,需要先將上一次測試時生成的表刪除,這樣才能測試出正確結果。
1)increment策略
該策略是 Hibernate 自己在維護主鍵的值。當準備在資料庫表中插入一條新記錄時,首先從資料庫表中獲取當前主鍵欄位的最大值,然後在最大值基礎上加 1,作為新插入記錄的
主鍵值,這就是 increment 生成策略。用其生成的主鍵欄位所對應的屬性型別可以是 long、short、int 及其封裝類的型別。這種生成策略只有在沒有其他程序向同一張表中插入資料時才能使用。在高併發下或叢集下不能使用。其測試情況是,後臺會產生對當前最大 id 的查詢語句。
2)identity 生成策略;
該策略使用資料庫自身的自增長來維護主鍵值。如 mysql 使用 auto_increment 來維護。
用其生成的主鍵欄位所對應的屬性型別可以是 long、short、int 及其封裝類的型別。
該策略在生成主鍵值時會出現以下情況:對於插入操作,即使最後的執行是回滾,DB中記錄主鍵值的變數也會增一。因為該生成策略在發生回滾之前已經呼叫過DB的主鍵自增,所以無論是否提交,對於 DB 來說已經執行。其測試情況是,後臺不會產生任何有關 id 生成值的語句。因為其使用的是 MySql 自身的 auto_increment 來為 id 賦值
3)sequence 生成策略
在 Oracle、DB2 和 PostgreSQL 等資料庫中建立一個序列(sequence),然後 Hibernate 通過該序列為當前記錄獲取主鍵值,從而為實體物件賦予主鍵欄位對映屬性值。此即 sequence生成策略,用其生成的主鍵欄位對映屬性值的型別可以是 long、short、int 及其封裝類的型別。對於 MySql 資料庫,原本是不支援序列的。但稍作修改後,MySql 也支援該生成策略。
其測試情況是:在第一次執行時,後臺會輸出以下查詢語句,並報錯。該語句是,從 hibernae_sequence 序列表中查詢欄位值 next_val,該值將作為要插入資料的主鍵值。當然,該查詢語句中的 for update 表示,對該表的操作使用了樂觀鎖。開啟資料庫,發現多生成了一張表 hibernate_sequence,開啟該表,發現其值為空,無法進行自增運算。這就是報錯的原因:沒有初始值。手工為其賦初值 1 即可再運行了
4)native 生成策略
由 Hibernate 根據所使用的資料庫支援能力從 identity、sequence 生成策略中選擇一種。
使用這種識別符號屬性生成策略可以根據不同的資料庫採用不同的生成策略,如 Oracle中使用 sequence,在MySQL 中使用 identity 便於 Hibernate 應用在不同的資料庫之間移植。試情況是,沒有生成任何與 id 生成值有關的 SQL 語句。說明使用的是 identity 生成策略
5)uuid 生成策略
uuid 生成策略採用 UUID( Universally Unique Identifier,通用唯一識別碼) 演算法來生成一個35字串型別的主鍵值,該值使用 IP 地址、JVM 的啟動時間(精確到 1/4 秒)、當前系統時間和一個計數器值(在當前的 JVM 中唯一)經過計算產生,可以用於分散式的 Hibernate 應用中。產生的識別符號屬性是一個 32 位長度的字串。使用這種生成策略,要求屬性的型別必須為 String 型別。這種識別符號屬性生成策略生成的數值可以保證多個數據庫之間的唯一性,並且由於其生成與具體的資料庫沒有關係,所以其移植性較強。但由於該值是 32 位長的字串,所以佔用的資料庫空間較大,並且檢索速度較慢。不過,實際開發中使用這種生成策略較多。除了使用 Hibernate 外,在 JDBC 中也可以使用 uuid 生成主鍵。因為 UUID 是 java.util 包中的一個獨立的類。可以開啟專案的 JRE System Library 庫中的 rt.jar,在其中找到 java.util包,即可看到 UUID 這個類。
6)assigned 生成策略
該生成策略的主鍵值來自於程式設計師的手工設定,即通過 setId()方法設定。屬性型別可以是整型,也可以是 String,但一般為 String。
此生成策略,主要應用於業務相關主鍵。例如學號、身份證號做主鍵。