Oto Main.java
:Czy istnieje bardziej przejrzysty sposób użycia funkcji prób z zasobami i PreparedStatement?
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();
}
}
}
A oto 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", "");
}
}
używam bazy danych H2 dla uproszczenia, ponieważ jest to jeden plik, który oparty jest łatwo tworzyć i testować dalej.
Tak więc wszystko działa i zasoby są oczyszczane zgodnie z oczekiwaniami, ale po prostu uważam, że może istnieć czystszy sposób ustawiania parametrów PreparedStatement
z bloku try-with-resources (i nie chcę używać zagnieżdżonych try/catch bloki, ponieważ te wyglądają "niezręcznie"). Być może istnieje już klasa pomocnicza w JDBC, która właśnie to robi, ale nie udało mi się jej znaleźć.
Najlepiej z funkcją lambda, aby zainicjować PreparedStatement
, ale nadal wymagałoby przydziału obiektu AutoCloseable
, aby mógł znajdować się w try-with-resources.
Prawdopodobny duplikat [Jak powinienem używać try-with-resources z JDBC?] (Http://stackoverflow.com/questions/8066501/how-should-i-usead-the-resources-with-jdbc) –
Mam nadzieję znaleźć sposób na zrobienie init dla PreparedStatement za pomocą lambda zamiast instancji klasy, prawie jak przesyłanie parametrów do PreparedStatement. – AlexC