java - setint - ¿Cómo obtener parámetros de PreparedStatement?
result set with preparedstatement in java (3)
Solución 1: Subclase
Simplemente cree una implementación personalizada de PreparedStatement que delegue todas las llamadas a la declaración original preparada, solo agregando devoluciones de llamada en los métodos setObject , etc. Ejemplo:
public PreparedStatement prepareStatement(String sql) {
final PreparedStatement delegate = conn.prepareStatement(sql);
return new PreparedStatement() {
// TODO: much more methods to delegate
@Override
public void setString(int parameterIndex, String x) throws SQLException {
// TODO: remember value of X
delegate.setString(parameterIndex, x);
}
};
}
Si desea guardar parámetros y obtenerlos más tarde, hay muchas soluciones, pero prefiero crear una nueva clase como ParameterAwarePreparedStatement que tenga los parámetros en un mapa. La estructura podría ser similar a esta:
public class ParameterAwarePreparedStatement implements PreparedStatement {
private final PreparedStatement delegate;
private final Map<Integer,Object> parameters;
public ParameterAwarePreparedStatement(PreparedStatement delegate) {
this.delegate = delegate;
this.parameters = new HashMap<>();
}
public Map<Integer,Object> getParameters() {
return Collections.unmodifiableMap(parameters);
}
// TODO: many methods to delegate
@Override
public void setString(int parameterIndex, String x) throws SQLException {
delegate.setString(parameterIndex, x);
parameters.put(parameterIndex, x);
}
}
Solución 2: proxy dinámico
Esta segunda solución es más corta, pero parece más hacky.
Puede crear un proxy dinámico llamando a un método de fábrica en java.lang.reflect.Proxy y delegar todas las llamadas en la instancia original. Ejemplo:
public PreparedStatement prepareStatement(String sql) {
final PreparedStatement ps = conn.prepareStatement(sql);
final PreparedStatement psProxy = (PreparedStatement) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class<?>[]{PreparedStatement.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("setLong")) {
// ... your code here ...
}
// this invokes the default call
return method.invoke(ps, args);
}
});
return psProxy;
}
Luego, intercepta las llamadas a setObject , etc. mirando los nombres de los métodos y buscando los argumentos del segundo método para sus valores.
Estoy escribiendo logger genérico para SQLException y me gustaría obtener los parámetros que se pasaron a PreparedStatement, ¿cómo hacerlo? Pude obtener la cuenta de ellos.
ParameterMetaData metaData = query.getParameterMetaData();
parameterCount = metaData.getParameterCount();
Respuesta corta: No puedes.
Respuesta larga: todos los controladores JDBC mantendrán los valores de los parámetros en algún lugar, pero no hay una forma estándar de obtenerlos.
Si desea imprimirlos para fines de depuración o similares, tiene varias opciones:
Cree un controlador JDBC de paso (use p6spy o log4jdbc como base) que guarde copias de los parámetros y ofrezca una API pública para leerlos.
Use Java Reflection API (
Field.setAccessible(true)
es su amigo) para leer las estructuras de datos privados de los controladores JDBC. Ese es mi enfoque preferido. Tengo una fábrica que delega en implementaciones específicas de base de datos que pueden decodificar los parámetros y que me permite leer los parámetros a través degetObject(int column)
.Presente un informe de error y solicite que se mejoren las excepciones. Especialmente Oracle es realmente tacaño cuando se trata de decirte lo que está mal.
Este artículo , de Boulder, ahtoulgh DB 2 "específico", ofrece un ejemplo completo del uso de ParameterMetadata.