Как получить параметры из PreparedStatement? - PullRequest
19 голосов
/ 14 января 2011

Я пишу общий регистратор для SQLException, и я хотел бы получить параметры, которые были переданы в PreparedStatement, как это сделать? Я смог получить их количество.

ParameterMetaData metaData = query.getParameterMetaData();
parameterCount = metaData.getParameterCount();

Ответы [ 3 ]

19 голосов
/ 14 января 2011

Краткий ответ: Вы не можете.

Длинный ответ: Все драйверы JDBC будут где-то хранить значения параметров, но стандартного способа их получения нет.

Если вы хотите напечататьих для отладки или аналогичных целей, у вас есть несколько вариантов:

  1. Создать сквозной драйвер JDBC (используйте в качестве основы p6spy или log4jdbc), который хранит копии параметров и предлагает открытыеAPI для их чтения.

  2. Используйте Java Reflection API (Field.setAccessible(true) - ваш друг) для чтения частных структур данных драйверов JDBC.Это мой предпочтительный подход.У меня есть фабрика, которая делегирует конкретным реализациям БД, которые могут декодировать параметры, и которая позволяет мне читать параметры через getObject(int column).

  3. Подать отчет об ошибке и попросить, чтобы исключения былиулучшенный.Особенно Оракул очень скуп, когда говорит, что не так.

6 голосов
/ 21 января 2015

Решение 1: Подкласс

Просто создайте пользовательскую реализацию PreparedStatement , которая делегирует все вызовы исходной подготовленной инструкции, добавляя только обратные вызовы в методах setObject и т. Д. Пример:

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);
            }
        };
    }

Если вы хотите сохранить параметры и получить их позже, есть много решений, но я предпочитаю создать новый класс, такой как ParameterAwarePreparedStatement , который имеет параметры на карте. Структура может быть похожа на это:

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);
    }
}

Решение 2: Динамический прокси

Это второе решение короче, но кажется более хакерским.

Вы можете создать динамический прокси, вызвав метод фабрики в java.lang.reflect.Proxy и делегировать все вызовы в исходном экземпляре. Пример: * +1021 *

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;
}

Затем вы перехватываете вызовы setObject и т. Д., Просматривая имена методов и просматривая аргументы второго метода для своих значений.

1 голос
/ 14 января 2011

В этой статье , из Boulder, ahtoulgh DB 2 "specific", приведен полный пример использования ParameterMetadata.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...