7

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

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

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

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

4

4 回答 4

14

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

因为在大多数RDBMS.

准备好的语句实际上是缓存的执行计划,不考虑您的权限、编码、排序规则设置等。

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

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

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

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

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

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

,其中绑定的参数将?在查询执行期间替换为 's。

如果你想要一个static方法:

  • 创建static连接句柄。
  • static使用参数化查询文本作为 a创建准备查询的哈希表key,并将准备查询的句柄作为 a value
  • 每当您想执行查询时,找到它的句柄(如果没有找到,则创建它)并使用 to 来绑定参数并执行查询。
于 2009-06-08T13:47:58.547 回答
1

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

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

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

您可能还想考虑使用诸如 Spring 之类的 API,它具有一系列JdbcTemplate类,可以将所有连接处理从您那里抽象出来,但仍然允许您使用Map.

于 2009-06-08T13:49:07.733 回答
1

您可能想要 Apache Commons 库中的 DbUtils 包:[ http://commons.apache.org/dbutils/index.html][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。这也适用于非更新/插入语句,即普通选择查询,并且创建 ResultSetHandlers 的能力使您能够将 ResultSet 转换为完全准备好的 bean 或带有键的 Map是列名,值是实际的行值。当您无法实现整个 ORM 解决方案时非常有用。

于 2009-06-08T15:15:54.657 回答
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);
            }
        }
    }
}
于 2009-06-08T14:26:40.107 回答