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

时间:2009-06-08 13:43:40

标签: java sql jdbc prepared-statement

我想为many reasons使用预先准备好的陈述。 但是,我想创建一个如下所示的方法:

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

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

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

4 个答案:

答案 0 :(得分:14)

  

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

因为这些陈述是在大多数RDBMS的基础上按连接准备的。

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

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

  

有没有办法在不使用String.format()

的情况下做我想做的事情

在这里看不出为什么需要String.format()

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

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

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

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

如果您想要static方法:

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

答案 1 :(得分:1)

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

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

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

您可能还希望使用一个API,例如Spring,它有一系列JdbcTemplate类,可以抽象出远离您的所有连接处理,但仍允许您使用Map

答案 2 :(得分:0)

通过让我调用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);
            }
        }
    }
}

答案 3 :(得分:0)

你可能想要像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解决方案时非常有用。