熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

如何在JAVA SE中使用Hibernate

2013-11-23 20:34:00  來源: Java開源技術 

  目前人們很容易發現Hibernate正迅速的成為流行的JEE的O/R映射工具和數據集成框架(如果不是最流行的)Hibernate為企業應用開發者操作關系數據庫的提供了清晰明了而又強大的工具然而如果你需要在外部訪問那些包裝在JEE web應用裡的實體情況又怎樣呢?你的開發跟應用獨立分開卻又相同的實體以訪問你的數據嗎?又或者你得編寫附加的web組件來管理對數據的內部訪問嗎?

  在很多情況下這些問題都會出現我的情況是我的公司需要將來自多個供應商有著多種文件格式的記錄導入到數據庫裡我想起我以前經常使用的方法那就是編寫Shell和SQL教本(甚至是存儲過程)來導入數據但是由於我們的數據模型太過復雜我決定在web應用之外盡可能的利用現有的實體Spring DAO以及服務並且開發一個自定義的JSE命令行數據加載工具

  大問題你該怎樣呢?

  現在很多Hibernate的文檔和范例都是綁定在容器上不管是web應用還是內部的大型應用總會使用到容器的人們有很好的理由去使用它容器是設計來提供對各種特性的支持例如事務處理線程以及安全現今這些特性都是開發中等規模和企業應用所必需的工具然而當你需要在容器之外訪問實體時你該怎樣呢?你是使用現有的架構和代碼呢還是會從一個不同的角度來解決問題比如說完全采用另一種開發語言?當然我們沒有正確答案在本文的余下部分我將說明我的方法就是在Spring容器之外重用現有的實體/POJO

  起初腳本語言例如PerlPythonRuby甚至Tcl(是的我以前也做過這個)看起來有很多優勢它們能省下很多時間可以輕易得到初始結果還能規避許多Hibernate潛在的復雜度人們完全可能只用幾行代碼就可以連接數據庫查詢結果已經打印輸出到終端屏幕或者日志文件然而取決於你的數據模型事情也(總是)會變得相當復雜譬如說你有一個表 person 其中有一個外鍵屬於表 address當我們添加數據的時候表address沒有正確的插入數據就會導致表person 也不能插入了這是個很典型的事務處理方面的問題也許有人會說在腳本語言中這個問題不難解決就像在你的主程序裡一樣可是問題仍然存在為什麼要這樣做呢?業務邏輯不是已經在你的應用裡面了嗎?為什麼要在寫一遍代碼呢?而且這並不是唯一的情況你必須重復你的工作和業務邏輯這樣就會帶來出錯的可能

  然而有些人會覺得這樣也行他們使用自己覺得最適合的工具也許你已經因為程序之外的原因而有了某種獨立的架構也許你會在獨立的數據庫裡加載和測試數據然後在通過各種測試後再遷移到產品的數據庫裡又也許你把數據庫維護外包出去你只需要把相關文件發給合作伙伴讓他們去處理那些問題總之總會有很多理由不使用現有的Hibernate數據層沒有誰對誰錯只是如果你可以也願意在你的應用之外使用現有的代碼請往下看我會告訴你一些方法這能解決你不少的煩惱噢

  配置

  如果你覺得可以在容器之外使用現有的Hibernate對象的話那你首先要做的事就是得自己手工管理所有的配置項在本文余下部分我所采用的方法是使用一個基於命令行的JAVA程序既然你已經配置了Hibernate XML配置文件你應該知道需要提供的參數例如JNDI DataSource名實體映射文件還有其他一些處理SQL日志的屬性如果你想使用命令行程序的話你就得解決如何解析XML文件和把它添加到配置項中的這些問題雖然解析XML文件也不難但這本身並不是我們的重點因此我建議使用propetries文件properties文件比較直觀而且容易加載並從中讀取數據下面是配置Hibernate所需要的最小屬性集(不包括任何實體映射)

  清單

  hibernatedialect=netsfhibernatedialectPostgreSQLDialect
nnectiondriver_class=orgpostgresqlDriver
nnectionurl=jdbc:postgresql://devserver/devdb
nnectionusername=dbuser
nnectionpassword=dbpassword
hibernatequerysubstitutions yes Y

  正如你所看到的上面的屬性值指定了數據庫方言JDBC驅動數據庫url用戶名用戶密碼以及是否使用查找替換只要定義以上幾項數值並保存在文件hibernateproperties裡(要放置在你的類路徑裡面哦)就能很輕松的加載填充到Hibernate Configuation類裡面

  清單

  Properties props = new Properties();
try {
    propsload(propsgetClass()getResourceAsStream(hibernateproperties));
}catch(Exception e){
    Systemoutprintln(Error loading hibernate properties);
    eprintStackTrace();
    Systemexit();
}

String driver = propsgetProperty(nnectiondriver_class);
String connUrl = propsgetProperty(nnectionurl);
String username = propsgetProperty(nnectionusername);
String password = propsgetProperty(nnectionpassword);            

// In my examples I use Postgres but Hibernate
// supports virtually every popular dbms out there
ClassforName(orgpostgresqlDriver);
Connection conn = DriverManagergetConnection(connUrl username password);

Configuration cfg = new Configuration();
cfgsetProperties( props );
SessionFactory sessions = cfgbuildSessionFactory();
Session session = sessionsopenSession(conn);

  這樣我們就得到了Hibernate Session類了但我們也有必要解決如何利用現有的實體映射這個問題在《Hibernate in Action》一書中提到怎樣從實體映射XML文件中加載如下所示

  清單

  Configuration cfg = new Configuration();
cfgaddResource(hello/Messagehbmxml);
cfgsetProperties( SystemgetProperties() );
SessionFactory sessions = cfgbuildSessionFactory();

  這段代碼清晰的說明了從hello包裡加載Message實體定義的過程對於這個例子來說還好但對那些有多個實體的應用來說就很單一而且容易出錯不僅映射關系是硬編碼還得手工管理每次添加一個新的實體就要更新實體加載的代碼其實有跟簡單的方法去查找和加載映射關系以使其與最新的jar文件保持一致

  首先在你的web服務器或者企業服務器裡映射文件需要放置在類路徑裡這樣Hibernate才能正常的運行這樣做是很有好處的因為你所需要做的就是使用同樣的jar包和查找相應的映射文件的名字因為你可能會有多個jar文件在你的類路徑裡你需要指定哪個jar包包含了映射文件以下就是一種查找映射關系的方法

  清單

  String cp = SystemgetProperty(javaclasspath);
String jarFile = null;
List hbmList = null;

String[] cparr = cpsplit(\\:);
for(int j=;j<cparrlength;j++){
    // The following assumes our entities
    // are wrapped up in a jar file
    // called dbobjsjar
    if(cparr[j]indexOf(dbobjsjar) != )
      jarFile=(cparr[j]);
}

if(jarFile != null){
    JarFile jar = new JarFile(new File(jarFile));
    Enumeration e = jarentries();
    if(ehasMoreElements()){
        hbmList = new ArrayList();
            while(ehasMoreElements()){
                // Object comes back as JarFile$JarFileEntry
                JarEntry entry = (JarEntry)enextElement();
                if(entrygetName()indexOf(hbmxml) != ){
                    hbmListadd(entrygetName());
                }
            }
    }else {
        Systemoutprintln(Error: The entity jar dbobjsjar was not found in +
        classpath: + cp);
    }
}

  上面的代碼主要完成了以下幾件事情獲取Java虛擬機初始化的classpath系統屬性查找含有實體映射文件的jar包解析映射文件的名字然後添加到一個ArrayList對象中去當我們的ArrayList對象裝滿了實體映射的名字後就可以將其傳遞到Hibernate Configuration 對象如下所示

  清單

  Configuration cfg = new Configuration();

Iterator iterator = erator();
while(iteratorhasNext()){
    cfgaddResource((String)iteratornext());
}

  只要我們在Hibernate Session 對象裡配置好正確的映射關系我們就可以將實體拿來使用了

  使用Session

  關於這一點你可以參考關於Hibernate和持久層的文章或者指南也可以查詢各種對象和實例來了解怎麼使用事務所以我不打算詳細說這些內容相反我會更多考慮使用實體後我們需要做什麼?這會對Hibernate Session 對象有怎樣的影響?是否可以使用現有的業務對象甚至是數據訪問對象?當我建立數據層的時候我使用了Spring及其提供的一些類來管理數據庫連接事務和會話這些對象都在XML配置文件裡面定義了並與很多規則和關系緊密集成在Spring裡首先通過Spring的依賴注射DAO對象會被引入到應用服務中(關於依賴注射參見Bruce Tate的《Five Things I Love About Spring》一書)然後配置應用服務以捕獲DAO異常(通過XML配置文件)讓Spring去處理可是因為我覺得把Spring集成到數據加載應用裡會帶來相當大的工作量我對DAO對象做了輕微的修改使得可以在web應用之外使用他們

  例如說在PersonDAO類裡面有一個保存person對象的方法如果Hibernate Session 是由容器建立的那這個方法就不能在容器外使用因為這需要一個配置好的Session對象以下是一個典型的PersonDAO它由Spring 容器提供了對Session的支持

  清單

  import orgspringframeworkormhibernateHibernateTemplate;
import testpojosPerson;

public class PersonDAO extends HibernateTemplate {

    public PersonDAO(){}

    public Person save(Person aPerson) {
        if(aPerson != null) supersave(person);
        return person;
    }
}

  上面的類繼承的是Spring HibernateTemplate 類它提供了各種不錯的使用Hibernate的基類方法而且由於HibernateTemplate類維護了大多數的常見操作你就只需要專注特定的持久層需求當然也應該有相應的異常處理但在本次范例當中只要以上的就夠了

  現在要在容器外加上對Session的支持我們只需要做一些小小的改動

  清單

  import orgspringframeworkormhibernateHibernateTemplate;
import netsfhibernateSession;
import testpojosPerson;

public class PersonDAO extends HibernateTemplate {

    public PersonDAO(){}

    public void setExternalSessionFactory(Session aSession){
        setSessionFactory(sessiongetSessionFactory());
    }

    public Person save(Person aPerson) {
        if(aPerson != null) supersave(person);
        return person;
    }
}

  因為HibernateTemplate類繼承於HibernateAccessor類我們就可以從任何Session對象中建立SessionFactory這是Spring小組的一個高靈活性的設計使得重用現有代碼更加容易

  也許你並沒有使用Spring而是采用完全不同的方法如果你不喜歡Spring的一來注射你也可以通過JNDI查找Session對象

  清單

  import netsfhibernateSession;

public class PersonDAO {

// This example assumes that there is a Hibernate
// Session object at the following JNDI location
// on a Tomcat server:
// java:/comp/env/obj/hibernateSession

    private Session session;

    public PersonDAO(){
        try {
            Context initCtx = new InitialContext();
            Context envCtx = (Context) initCtxlookup(java:comp/env);
            session = (Session)envCtxlookup(obj/hibernateSession);
        }catch(Exception e) {
            eprintStackTrace();
        }
    }

    public Person save(Person aPerson) {
        if(aPerson != null) sessionsave(person);
        return person;
    }
}

  以上的例子依賴於應用服務器來使得Hibernate Session對象可用在容器之外使用的最簡單方法就是添加一個帶Session參數的構造函數如下所示

  清單

  import netsfhibernateSession;

public class PersonDAO {

// This example assumes that there is a Hibernate
// Session object at the following JNDI location
// on a Tomcat server:
// java:/comp/env/obj/hibernateSession

    private Session session;

    public PersonDAO(){
        try {
            Context initCtx = new InitialContext();
            Context envCtx = (Context) initCtxlookup(java:comp/env);
            session = (Session)envCtx lookup(obj/hibernateSession);
        }catch(Exception e) {
            eprintStackTrace();
        }
    }

    public PersonDAO(Session aSession){
        session = aSession;
    }

    public Person save(Person aPerson) {
        if(aPerson != null) sessionsave(person);
        return person;
    }
}

  當然我們並沒有處理太多的異常事務問題甚至我們在多個方法內共用一個Session對象這會導致一些並發事務問題(取決於容器或框架如何處理對象實例)不過我想很顯然以上的例子演示了如何重用大量的現有數據層代碼只需要一點點有創造力的想法要弄清楚你是否想在應用服務器之外使用現有的實體和DAO接下來就不斷嘗試把

  結論

  正如你所見要在web容器外使用Hibernate 實體和DAO是需要技巧的但這肯定能做到的最大的困難在於如何查找實體映射關系和如何重設置(或者說修改)現有的數據訪問對象(即DAO)處理後者時要小心處理事務問題因為沒有應用服務可以依賴了不過最後我們還是可以訪問所有的實體和進行持久化的對象這樣能省下大量的重新開發代碼的時間祝您好運!!


From:http://tw.wingwit.com/Article/program/Java/ky/201311/28684.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.