官术网_书友最值得收藏!

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標準在面向對象特性處理方面的支持非常有限,無法支持繼承、多態和復雜關系等面向對象的高級特性。

主站蜘蛛池模板: 清徐县| 安义县| 元阳县| 黄骅市| 娄烦县| 永寿县| 临安市| 泽库县| 磐石市| 遂平县| 错那县| 山阴县| 肥城市| 长宁区| 龙门县| 冷水江市| 道孚县| 政和县| 子长县| 图木舒克市| 德兴市| 和硕县| 余江县| 渑池县| 兰溪市| 洛川县| 贵港市| 晋城| 石河子市| 泰安市| 阿克苏市| 上栗县| 武汉市| 麻江县| 庄河市| 宜章县| 钦州市| 福泉市| 宾川县| 北川| 车险|