2009-06-08 201 views
6

我想用準備的語句,爲many reasons。 但是,我想創建一個類似如下的方法:爲什麼我需要一個連接來創建PreparedStatements?

/* This opens a connection, executes the query, and closes the connection */ 
public static void executeNonQuery(String queryString); 

換句話說,我希望我的應用程序邏輯,只需要制定查詢和參數的飼料,但不能與連接&報表處理。然而,PreparedStatements是從一個連接對象創建的,所以我現在被迫使用String.format()來準備查詢字符串 - 對接醜陋而且很危險。

有沒有辦法做到我想要的而不使用String.format()?

+0

您的executeNonQuery方法有一個問題:獲取連接。如果每次執行此方法時都創建一個,則會反覆執行性能問題(創建和關閉連接很昂貴)。如果這封裝在僅在首次調用時創建連接的對象上,則會出現問題:什麼時候關閉它?也許基於時間?如果您使用靜態字段進行緩存,請注意不會收集。不過,在緩存連接時,要小心併發調用:如果沒有鎖定機制(例如syncrhonized),則可以創建大量連接。 – 2009-06-08 15:18:07

回答

14

爲什麼我需要一個連接來創建PreparedStatements?

因爲這些報表是根據大多數RDBMS的每個連接準備的。

準備好的語句實際上是高速緩存的執行計劃,它不會將您的權限,編碼,排序規則設置等考慮在內。

所有這些都是在查詢分析過程中完成的。

有沒有辦法做我想做什麼不使用String.format()

不明白爲什麼你需要String.format()在這裏。

您可以將您的查詢作爲類實現,創建連接並在類構造函數中準備查詢,然後在方法中執行查詢。

甲參數化查詢通常看起來像這樣:

SELECT * 
FROM table 
WHERE col1 = ? 
     AND col2 = ? 

,其中所述結合的參數將在查詢執行過程中被替換爲?的。

如果你想有一個static方法:

  • 創建static連接句柄。
  • 使用參數化查詢文本創建static已準備查詢的哈希表作爲key,並將準備好的查詢的句柄作爲value
  • 無論何時你想執行一個查詢,找到它的句柄(或者如果找不到它,就創建它)並使用它來綁定參數並執行查詢。
1

爲什麼不讓你的「應用程序」邏輯使用你創建的可以呈現這種接口方法的數據層?

然後,您的數據層可以處理創建連接,準備語句等,所有這些都在executeNonQuery方法中。

我認爲如果您試圖將查詢/語句中的參數自己合併到一個字符串中,那麼您正在拍攝自己的腳並且實際上不使用PreparedStatements的參數功能。不知道你爲什麼想要這樣做。

您可能還想使用Spring之類的API進行研究,該API有一系列JdbcTemplate類,可以將所有連接處理從您身邊抽象出來,但仍允許您使用Map中的參數。

0

我通過讓一個類調用QueryRunner抽象出所有的JDBC東西,該類具有一個執行方法,該方法使用sql,一個表示參數的對象列表以及一個將處理ResultSet的對象。如果使用JDBC中的setObject方法來設置參數,它將根據基礎對象計算出適當的DB類型。這是我的代碼的一部分。我有另一種方法來封裝這個並獲得連接。

public void executeNoCommit(Connection conn, 
          String sql, 
          List params, 
          ResultSetProcessor processor) throws SQLException { 
    PreparedStatement stmt = null; 
    ResultSet rs = null; 
    int updateCount = 0; 
    Iterator it; 
    int paramIndex = 1; 
    boolean query; 

    try { 
     stmt = conn.prepareStatement(sql); 

     if (params != null) { 
      it = params.iterator(); 
      while (it.hasNext()) { 
       stmt.setObject(paramIndex, it.next()); 
       paramIndex++; 
      } 
     } 

     query = stmt.execute(); 
     if (query) { 
      rs = stmt.getResultSet(); 
     } 
     else { 
      updateCount = stmt.getUpdateCount(); 
     } 

     processor.process(rs, updateCount); 
    } 
    finally { 
     if (rs != null) { 
      try { 
       rs.close(); 
      } 
      catch (SQLException e) { 
       log.error(e); 
      } 
     } 

     if (stmt != null) { 
      try { 
       stmt.close(); 
      } 
      catch (SQLException e) { 
       log.error(e); 
      } 
     } 
    } 
} 
+0

你可以發佈代碼嗎? – ripper234 2009-06-08 14:43:24

0

你可能想在Apache的共享庫類似的DbUtils包:http://commons.apache.org/dbutils/index.html][1]

的QueryRunner類,您可以執行SQL語句,而無需手動創建的PreparedStatement,甚至有一個開放的連接物。從實例頁:

QueryRunner run = new QueryRunner(dataSource); 
try 
{ 
    // Create an object array to hold the values to insert 
    Object[] insertParams = {"John Doe", new Double(1.82)}; 
    // Execute the SQL update statement and return the number of 
    // inserts that were made 
    int inserts = run.update("INSERT INTO Person (name,height) VALUES (?,?)", 
           insertParams); 

    // Now it's time to rise to the occation... 
    Object[] updateParams = {new Double(2.05), "John Doe"}; 
    int updates = run.update("UPDATE Person SET height=? WHERE name=?", 
           updateParams); 
} 
catch(SQLException sqle) { 
    // Handle it 
} 

因此,它基本上處理的預處理語句創建透明,你真的需要知道的唯一事情是一個數據源。這也適用於非更新/插入語句,即簡單香草選擇查詢,並且創建ResultSetHandlers的能力使您能夠將ResultSet轉換爲類似完全準備的bean或具有鍵的Map是列名稱,值是實際的行值。當您無法實施整個ORM解決方案時非常有用。

相關問題