为什么我需要连接来创建PreparedStatements?

出于多种原因 ,我想使用准备好的陈述。 但是,我想创建一个如下所示的方法:

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

换句话说,我希望我的应用程序逻辑只需要制定查询和feed参数,而不是处理连接和语句。 但是,PreparedStatements是从连接对象创建的,所以我当前被迫使用String.format()准备查询字符串 – 但是很丑陋且危险。

有没有办法在不使用String.format()的情况下做我想做的事情?

为什么我需要连接来创建PreparedStatements?

因为这些语句是在大多数RDBMS基于每个连接准备的。

准备好的语句实际上是缓存的执行计划,不会考虑您的权限,编码,整理设置等。

所有这些都是在查询解析期间完成的。

有没有办法在不使用String.format()情况下做我想做的事情

不明白为什么你需要String.format()

您可以将查询实现为类,创建连接并在类构造函数中准备查询,然后在方法中执行它。

参数化查询通常如下所示:

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

,绑定参数将被替换? 在查询执行期间。

如果你想要一个static方法:

  • 创建static连接句柄。
  • 使用参数化查询文本作为key创建准备好的查询的static哈希表,并将准备好的查询的句柄作为value
  • 每当您想要执行查询时,找到它的句柄(或者如果找不到它就创建它)并使用来绑定参数并执行查询。

为什么不让您的“应用程序”逻辑使用您创建的可以呈现这种接口方法的数据层?

然后,您的数据层可以处理在executeNonQuery方法中创建连接,准备语句等。

我认为如果你试图将查询/语句中的参数自己合并到一个字符串中,那么你就是在自己的脚下拍摄,而实际上并没有使用PreparedStatements的参数function。 不知道你为什么要这样做。

您可能还希望使用诸如Spring之类的API,它具有一系列JdbcTemplate类,可以抽象远离您的所有连接处理,但仍允许您使用Map参数。

我通过让我调用QueryRunner的类来抽象出所有JDBC的东西,该类具有一个带有sql的execute方法,一个表示参数的对象List,以及一个将处理ResultSet的对象。 如果使用JDBC中的setObject方法设置参数,它将根据底层对象确定要使用的相应数据库类型。 这是我的一部分代码。 我有另一个方法来包装这个并获得连接。

 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); } } } } 

你可能想要像Apache Commons库中的DbUtils包这样的东西:[ http://commons.apache.org/dbutils/index.html%5D [1 ]

QueryRunner类允许您执行sql语句,而无需手动创建PreparedStatements,甚至可以打开连接。 从示例页面:

 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 } 

因此它基本上透明地处理预准备语句的创建,而您真正需要知道的唯一事情是DataSource。 这也适用于非更新/插入语句,即普通选择查询,并且创建ResultSetHandler的function使您能够将ResultSet转换为类似完全准备好的bean或带有键的Map。作为列名,值是实际的行值。 当您无法实现整个ORM解决方案时非常有用。