Заранее заданный вопрос в Java против Oracle

Я работаю над модификацией некоторого кода для использования prepareStatement вместо обычного Statement для обеспечения безопасности и производительности.

В настоящее время наше приложение хранит информацию во встроенной базе данных derby, но мы скоро перейдем к Oracle.

Я нашел две вещи, которые мне нужны для помощи ребятам о Oracle и подготовленном заявлении:

1- Я нашел этот документ, говорящий, что Oracle не обрабатывает параметры привязки в предложениях IN, поэтому мы не можем предоставить запрос например:

Select pokemon from pokemonTable where capacity in (?,?,?,?)

Это правда? Есть ли обходной путь?... Зачем?

2- У нас есть некоторые поля типа TIMESTAMP. Таким образом, с нашим фактическим Statement запрос выглядит следующим образом:

Select raichu from pokemonTable where evolution = TO_TIMESTAMP('2500-12-31 00:00:00.000', 'YYYY-MM-DD HH24:MI:SS.FF')

Что нужно сделать для подготовленного Заявления? Должен ли я помещать в массив параметров: 2500-12-31 или TO_TIMESTAMP ('2500-12-31 00: 00: 00.000', 'YYYY-MM-DD HH24: MI: SS.FF')?

Спасибо за вашу помощь, надеюсь, мои вопросы ясны!

Привет,

Ответы

Ответ 1

Я немного удивлен, увидев этот документ. Верно, что вы не можете установить массив/коллекцию, как показано ниже (и это независимо от используемого драйвера базы данных /JDBC ):

String sql = "SELECT col FROM tbl WHERE id IN (?)";
statement = connection.prepareStatement(sql);
statement.setArray(1, arrayOfValues); // Fail.

Но в упомянутом документе запрос должен работать. Я могу сказать это по опыту, по крайней мере, с Oracle 10g XE в сочетании с ojdbc14.jar. Я подозреваю, что либо автор документа смутил вещи, либо фактически относится к другой (более старой?) Версии драйвера DB и/или JDBC.

Следующее должно работать независимо от используемого драйвера JDBC (хотя вы зависите от БД, использовали количество элементов, которые может содержать предложение IN, Oracle (да, опять) имеет ограничение около 1000 элементов):

private static final String SQL_FIND = "SELECT id, name, value FROM data WHERE id IN (%s)";

public List<Data> find(Set<Long> ids) throws SQLException {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;
    List<Data> list = new ArrayList<Data>();
    String sql = String.format(SQL_FIND, preparePlaceHolders(ids.size()));

    try{
        connection = database.getConnection();
        statement = connection.prepareStatement(sql);
        setValues(statement, ids.toArray());
        resultSet = statement.executeQuery();
        while (resultSet.next()) {
            Data data = new Data();
            data.setId(resultSet.getLong("id"));
            data.setName(resultSet.getString("name"));
            data.setValue(resultSet.getInt("value"));
            list.add(data);
        }
    } finally {
        close(connection, statement, resultSet);
    }

    return list;
}

public static String preparePlaceHolders(int length) {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < length;) {
        builder.append("?");
        if (++i < length) {
            builder.append(",");
        }
    }
    return builder.toString();
}

public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
    for (int i = 0; i < values.length; i++) {
        preparedStatement.setObject(i + 1, values[i]);
    }
}

Что касается вопроса TIMESTAMP, просто используйте PreparedStatement#setTimestamp().