- EJB JPA數據庫持久層開發實踐詳解
- 馮曼菲等編著
- 2833字
- 2018-12-29 15:14:01
1.2 Java持久化技術
在Java領域中,持久化也是企業應用開發中一項必不可少的技術。Java社區在努力解決持久化數據管理的過程中,曾經涌現出了非常多試圖解決這個問題的技術方案。從最早的序列化(Serialization)到JDBC、關系對象映射(ORM)、對象數據庫(ODB),再到EJB 2.X、Java數據對象(JDO),一直到目前最新的Java持久化API(JPA)。
下面簡單地回顧一下在JPA出現之前,Java社區中曾經試圖為持久化數據管理提供完整解決方案的技術。
1.2.1 序列化(Serialization)
序列化(Serialization)也叫串行化,是Java內置的持久化Java對象的機制。只要某個類實現了java.io.Serializable接口,就能夠使用java.io.ObjectOutputStream將該類對象以二進制字節碼的形式寫到硬盤上,并能使用java.io.ObjectInputStream將該對象從硬盤上還原。這樣,即使重啟了機器,該Java對象也能夠從硬盤上恢復。
對應簡單的應用,可以使用序列化實現對Java對象的持久化。序列化的對象一般為普通的Java Bean。
例如下面的Person類,為一個普通的Java Bean,Person類只有name和hobby兩個屬性,代碼如下:
Person.java
package com.fengmanfei.intro;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Person implements Serializable {
private static final long serialVersionUID = -3067867193032937191L;
private String name;//姓名
private List<String> hobby = new ArrayList<String>();//愛好
//獲得愛好的Getter方法
public List<String> getHobby() {
return hobby;
} //設置愛好的Setter方法
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
//獲得姓名的Getter方法
public String getName() {
return name;
}
//設置姓名的Setter方法
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "姓名: " + name + ", 愛好: " + hobby;
}
}
使一個普通Java類可序列化,要注意以下幾個方面。
●類一定要實現Serializable接口,并聲明一個private static final的long類型的serialVersionUID屬性,如上面代碼中加粗部分所示。
● 類所有屬性也需要是可序列化的。Person類中,屬性name為String類型,屬性hobby為ArrayList類型。String和ArrayList都是實現了Serializable接口,也是可序列化的。
● 這樣,可序列化的類可以通過ObjectOutput類中的writeObject方法和readObject保存和讀取。
下面編寫一個簡單的對象序列化與還原程序,當輸入“save”后,然后依次輸入人員,最后保存;當輸入“load”后,然后輸入人員名稱,自動將匹配的人員查找出來,并且顯示其信息。該程序運行后,效果如圖1-2所示。

圖1-2 對象序列化程序運行結果
該程序的源代碼如下所示。
Console.java
package com.fengmanfei.intro;
import java.io.*;
import java.util.Arrays;
public class Console {
// 當前文件夾
public static File directory = new File(System.getProperty("user.dir"));
// 控制臺輸入
public static String systemRead() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
return reader.readLine();
}
// 將 person 對象持久化到硬盤上
public static void persist(Person person) throws IOException {
File file = new File(directory, person.getName() + ".dat");
ObjectOutput output = new ObjectOutputStream(new FileOutputStream(file));
//保存對象
output.writeObject(person);
output.close();
System.out.println("文件保存在:" + file);
}
// 將 person 對象從硬盤上恢復
public static Person load(String name) throws Exception {
File file = new File(directory, name + ".dat");
if (!file.exists())
return null;
ObjectInput ins = new ObjectInputStream(new FileInputStream(file));
//讀取對象
return (Person) ins.readObject();
}
public static void main(String[] args) throws Exception {
System.out.println("人員信息管理系統. ");
System.out.println("1. 輸入'save'開始錄入人員信息. ");
System.out.println("2. 輸入'load'開始查詢人員信息. ");
System.out.println("3. 輸入'exit'退出系統. ");
System.out.print("請輸入(回車結束輸入): ");
//獲取用戶輸入信息
String menu = systemRead();
//如果輸入的為save,則繼續輸入人員的姓名、愛好
if ("save".equalsIg否reCase(menu)) {
System.out.print("請輸入要錄入的人員姓名: ");
//獲得輸入人員的姓名
String name = systemRead();
System.out.print("請輸入'" + name + "'的愛好,用','隔開:");
//獲得輸入人員的愛好
String hobbies = systemRead();
//創建人員對象
Person person = new Person();
person.setName(name);
person.setHobby(Arrays.asList(hobbies.split(",")));
//持久化人員對象
persist(person);
//如果輸入的為load,則繼續查找人員的姓名,然后根據姓名查詢該人員的信息
} else if ("load".equalsIg否reCase(menu)) {
System.out.print("請輸入要查找的人員姓名:");
//獲得輸入人員的姓名
String name = systemRead();
//根據姓名查詢人員,并返回人員相關信息
Person person = load(name);
if (person == null)
System.out.println("沒有此人信息。");
else
System.out.println("查詢結果: " + person);
//如果輸入的為exit,則退出程序
} else if ("exit".equalsIg否reCase(menu)) {
System.out.println("再見. ");
System.exit(0);
//否則,提示錯誤信息
} else {
System.out.println("無效輸入: " + menu);
}
System.out.println();
// 繼續執行main主函數
main(null);
}
}
在實際的應用中,Tomcat的會話(Session)中使用的就是序列化技術。當Tomcat關閉的時候,Tomcat會把Session中的Java對象通過序列化保存到硬盤上,這樣,重啟Tomcat時又會把這些對象還原并重新放回Session中。因此,保存在Session中的對象最好實現Serializable接口。
雖然序列化使用起來快速、高效,能夠直接持續化Java對象,但是缺陷也很明顯,比如不能進行復雜查詢,可序列化的類結構、serialVersionUID值都不能發生改變(否則恢復時會出錯)等。
1.2.2 JDBC
JDBC(Java Database Connectivity)是最常用的持久化方法,它能夠把數據保存進關系型數據庫,并且高效地將數據從數據庫中查詢出來。JDBC作為一種成熟的持久化方法,與序列化技術相比,其優勢是相當明顯的。它能快速地讀寫大量的數據、支持事務性、保證數據的完整性、支持數據的并發讀取等。也正是因為如此,JDBC作為Java的持久化技術,廣泛用在各種商業程序中。
但美中不足的是,JDBC并不支持對Java對象的持久化。由于數據庫大多數是二維的關系型數據庫,因此持久化Java對象的時候,需要將Java對象變成相應的SQL語句;還原Java對象的時候,需要從數據庫結果集中取出各列的值,然后通過setter方法設置到Java對象上。
例如,使用JDBC技術,持久化Person對象時可能需要使用SQL代碼,將數據保存到數據庫中,示例如下所示。
PersonDAO.java
public void persist(Person person) throws Exception { //獲得數據庫連接 Connection conn = DbManager.getConnection(); PreparedStatement preStmt = null; try { //創建預編譯對象 preStmt = conn.prepareStatement(" " + " INSERT INTO tb_person ( name ) values (?) "); preStmt.setString(1, person.getName()); //插入一條人員數據 preStmt.executeUpdate(); //分別插入愛好數據 for (String hobby : person.getHobby()) { preStmt = conn.prepareStatement(" INSERT INTO tb_hoby " + " ( person_name, hoby ) " + " values (?, ?) "); preStmt.setString(1, person.getName()); preStmt.setString(2, hobby); //執行插入操作 preStmt.executeUpdate(); } } catch (Exception e) { preStmt.close(); conn.close(); } }
通過以上代碼可以看出,使用JDBC持久化Java對象時需要寫大量的SQL語句,當數據表結構或Java對象屬性發生變化的時候,JDBC的缺點就更加明顯了。
1.2.3 關系對象映射(ORM)
ORM(Object-Relational Mapping)是針對JDBC不能直接持久化Java對象的解決方案。ORM框架能夠將Java對象映射到關系數據庫,能夠直接持久化復雜的Java對象。在操作持久化Java對象的時候ORM框架會自動更新相應的一個或多個數據表。
ORM框架的出現,使開發者從數據庫編程中解脫出來,把更多的精力放在了業務模型與業務邏輯上。目前比較流行的ORM框架有Hibernate、iBatis、TopLink等。
ORM框架技術目前已經很成熟,并且已經在眾多商業項目中使用。但在JPA規范出臺之前,由于沒有官方的標準,使得各ORM框架之間的API差別很大,使用了某種ORM框架的系統會嚴重受制于該ORM的標準。例如一個使用Hibernate完成的系統,將無法改用iBatis。有關對象關系映射的相關知識,將在第1.4節詳細講述。
1.2.4 對象數據庫(ODB)
ODB(Object Database,面向對象數據庫)是數據庫技術發展的趨勢之一。面向對象數據庫的目標是能夠直接保存Java對象。目前市面上已經有幾種比較成熟的面向對象數據庫產品,例如DB4O等。
面向對象數據庫使用簡單,雖然擁有關系數據庫組織(Object Database Management Group ,ODMG)規定了持久化Java對象的標準API,但是大多數的面向對象數據庫目前位置都沒有遵循這個API。而且相對于理論上很完善、數據容量達到TB級的關系數據庫,面向對象數據庫還有技術上、效率上的不足。
面向對象數據庫目前主要應用于嵌入式系統、演示程序、小數據量程序等。
1.2.5 Java數據對象(JDO)
JDO(Java Data Object)是Java EE標準中除JPA外,另一個支持管理持久化數據的規范,但與JPA不同的是,它通常是通過JCA技術集成到應用服務器上。JDO不能夠支持容器級別的聲明式安全、事務等特性,也無法對遠程方法調用提供支持,是針對輕量級容器而設計的持久化規范。
1.2.6 EJB 2.X
EJB 2.X中的實體Bean是EJB組件中管理持久化數據的組件框架。與ORM框架類似,EJB 2.X實體Bean提供對Java對象持久化的功能,但與ORM框架不同的是,EJB 2.X實體Bean不僅僅局限于數據庫,也可以持久化EIS(Enterprise Information System)信息和其他持久化設備。
EJB 2.X實體Bean最大的缺點是規定了太過于嚴格的標準,這些標準雖然保證了企業應用能夠在不同的EJB容器之間可以移植,但是也讓EJB2.X實體Bean規范變得非常復雜并且開發起來十分復雜。同時EJB 2.X標準在面向對象特性處理方面的支持非常有限,無法支持繼承、多態和復雜關系等面向對象的高級特性。