2009-06-08 202 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解决方案时非常有用。

相关问题