2014-02-17 35 views
2

我有些現有的Java代碼在多個DAO類的形式,例如途徑JDBC連接在Servlet/JSP應用

class EmployeeDao {  

    public EmployeeDao(Connection conn) { 
     // Prepare statements to be used by the methods below 
    } 

    public Employee getEmployeeById(long id) { 
    } 

    public Collection<Employee> getEmployeesByDepartment(long departmentId) { 
    } 
    ... 
} 

所有DAO類構造有一個JDBC連接。構造器準備任何方法所需的語句。這在單線程環境(例如批處理)中可以很好地工作,調用者可以創建連接並使用該連接實例化所需的Dao對象。

我希望能夠在Java Web應用程序使用,但我只是不知道如何處理的JDBC連接。這裏有一些想法:

  1. 每個請求創建一個新的JDBC連接並實例化所需的Dao對象。從連接創建和Dao實例化開始,代價很明顯

  2. 每個請求都會從JNDI數據源中獲取連接並實例化所需的Dao對象。這消除了連接創建的開銷,但保留了準備所有語句的開銷

  3. 每個請求都從JDNI數據源獲取連接並實例化所需的Dao對象,但語句不再由構造函數準備,它們根據需要懶洋洋地準備。

  4. 甲HttpSessionListener實例中(通過使用setAttribute)會話中的DAO對象,並將它們存儲。會話過期時,連接關閉。

  5. 創建一個無狀態會話bean。該bean將實例化所需的Dao對象。

選項1不是真正的競爭者,它只是在那裏展示我的思維過程。

選項2和3的工作,但似乎是次優的,不必在每次請求準備的語句似乎是一個開銷,應該是很容易避免的,但我覺得我失去了如何

選項4避免在每個呼叫中​​都有準備報表的開銷,但是以手動維護狀態爲代價。我不認爲這是Servlet/JSP應用程序中的預期使用模式(長時間保持連接)。

選5應該工作,但似乎是一個很大的開銷,並且意味着我需要一個完整的EJB容器,而不是一個簡單的servlet引擎。

什麼方法已爲人們銘記的目標努力:在可能的話

  • 每個請求

    1. 避免準備語句最好使用一個簡單的servlet引擎

    PS:我知道像Hibernate和Entity Beans這樣的框架可以抽象出一些這樣的內容,但是我想要解決「無框架」的基礎案例。

  • 回答

    5

    我會建議你使用像你可以在每一個主要的應用程序服務器找到的那些數據庫連接池(或任何像樣的實現像DBCP,C3P0,等等。)

    Spring可以在(或多或少)緩存的dao實例中注入對數據源的引用,因此可以抓取更多的性能(時間以及內存消耗)。

    但是,我會說你每次都準備好你的語句,不要試圖緩存它們,因爲它們仍然鏈接到它們從中創建的連接,而這些連接由數據源管理。

    最後,關於你準備陳述的時間問題:如果你仔細寫下你的問題,這可能是疏忽大意的。準備聲明的行爲沒有消耗時間;查詢計劃非常繁重,這是在數據庫中完成的,在幕後。這就是您的「第一次」執行查詢似乎更耗時的原因。但是,如果將參數化查詢寫入您的語句中,數據庫將緩存您的查詢執行計劃並在其後的每個查詢執行中重複使用它。例如:

    PreparedStatement stmt = conn.prepareStatement("select name from employees where number = ?"); 
    

    是可緩存,以及查詢計劃將在每次你準備此語句時被重用(數據庫「記住」它編寫的另一個說法)

    然而,這樣的:

    PreparedStatement stmt = conn.prepareStatement("select name from employees where number = " + employeeNumber); 
    

    意味着您的數據庫每次準備語句時都必須準備一個不同的執行計劃(它不會「記住」該查詢) - 性能問題將以我構建查詢的方式而不是java Statement對象。更不用說這種方式是不安全的,並且也傾向於SQL注入。

    我希望你覺得這個有用

    +0

    特別感謝,關於緩存查詢計劃的重點,我還沒有完全註冊。 – PhilDin