gpt4 book ai didi

java - 有没有更简洁的方法来使用 try-with-resource 和 PreparedStatement?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:18:25 24 4
gpt4 key购买 nike

这是Main.java:

package foo.sandbox.db;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Main {
public static void main(String[] args) {
final String SQL = "select * from NVPAIR where name=?";
try (
Connection connection = DatabaseManager.getConnection();
PreparedStatement stmt = connection.prepareStatement(SQL);
DatabaseManager.PreparedStatementSetter<PreparedStatement> ignored = new DatabaseManager.PreparedStatementSetter<PreparedStatement>(stmt) {
@Override
public void init(PreparedStatement ps) throws SQLException {
ps.setString(1, "foo");
}
};
ResultSet rs = stmt.executeQuery()
) {
while (rs.next()) {
System.out.println(rs.getString("name") + "=" + rs.getString("value"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

这里是 DatabaseManager.java

package foo.sandbox.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

/**
* Initialize script
* -----
* CREATE TABLE NVPAIR;
* ALTER TABLE PUBLIC.NVPAIR ADD value VARCHAR2 NULL;
* ALTER TABLE PUBLIC.NVPAIR ADD id int NOT NULL AUTO_INCREMENT;
* CREATE UNIQUE INDEX NVPAIR_id_uindex ON PUBLIC.NVPAIR (id);
* ALTER TABLE PUBLIC.NVPAIR ADD name VARCHAR2 NOT NULL;
* ALTER TABLE PUBLIC.NVPAIR ADD CONSTRAINT NVPAIR_name_pk PRIMARY KEY (name);
*
* INSERT INTO NVPAIR(name, value) VALUES('foo', 'foo-value');
* INSERT INTO NVPAIR(name, value) VALUES('bar', 'bar-value');
*/
public class DatabaseManager {
/**
* Class to allow PreparedStatement to initialize parmaters inside try-with-resource
* @param <T> extends Statement
*/
public static abstract class PreparedStatementSetter<T extends Statement> implements AutoCloseable {
public PreparedStatementSetter(PreparedStatement pstmt) throws SQLException {
init(pstmt);
}

@Override
public void close() throws Exception {
}

public abstract void init(PreparedStatement pstmt) throws SQLException;
}

/* Use local file for database */
private static final String JDBC_CONNECTION = "jdbc:h2:file:./db/sandbox_h2.db;MODE=PostgreSQL";

static {
try {
Class.forName("org.h2.Driver"); // Init H2 DB driver
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* @return Database connection
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(JDBC_CONNECTION, "su", "");
}
}

我使用 H2 数据库是为了简单起见,因为它是一种基于文件的数据库,易于创建和测试。

所以一切正常,资源按预期清理,但我只是觉得可能有一种更简洁的方法来设置 try-with-resources block 内的 PreparedStatement 参数(我不不想使用嵌套的 try/catch block ,因为它们看起来“笨拙”)。也许 JDBC 中已经存在一个帮助程序类来执行此操作,但我还没有找到。

最好使用 lambda 函数来初始化 PreparedStatement,但它仍然需要分配一个 AutoCloseable 对象,以便它可以在 try-with-resources 中。

最佳答案

首先,您的 PreparedStatementSetter 类很笨拙:

  • 它是一个类型类,但没有使用类型。
  • 构造函数正在显式调用可重写方法,which is a bad practice .

请考虑以下接口(interface)(灵感来自同名的 Spring interface)。

public interface PreparedStatementSetter {
void setValues(PreparedStatement ps) throws SQLException;
}

此接口(interface)定义了 PreparedStatementSetter 应该做什么的约定:设置 PreparedStatement 的值,仅此而已。

那么,最好在单个方法中创建和初始化 PreparedStatement。考虑在您的 DatabaseManager 类中添加:

public static PreparedStatement prepareStatement(Connection connection, String sql, PreparedStatementSetter setter) throws SQLException {
PreparedStatement ps = connection.prepareStatement(sql);
setter.setValues(ps);
return ps;
}

使用这个静态方法,你可以这样写:

try (
Connection connection = DatabaseManager.getConnection();
PreparedStatement stmt = DatabaseManager.prepareStatement(connection, SQL, ps -> ps.setString(1, "foo"));
ResultSet rs = stmt.executeQuery()
) {
// rest of code
}

注意 PreparedStatementSetter 是如何用 lambda 表达式编写的。这是使用接口(interface)而不是抽象类的优势之一:在这种情况下它实际上是一个功能接口(interface)(因为只有一个抽象方法),因此可以写成 lambda。

关于java - 有没有更简洁的方法来使用 try-with-resource 和 PreparedStatement?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33703905/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com