PreparedStatement вопрос в Java против Oracle - PullRequest
1 голос
/ 24 марта 2010

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

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

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

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

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

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

2- У нас есть несколько полей типа TIMESTAMP. Итак, с нашим фактическим оператором запрос выглядит так:

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', 'ГГГГ-ММ-ДД ЧЧ24: MI: SS.FF')?

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

С уважением,

Ответы [ 2 ]

1 голос
/ 29 марта 2019

Oracle обрабатывает параметры связывания в предложении IN, но ожидает, что каждый параметр связывает одно значение типа, совместимого с выражением перед ключевым словом IN. То, что вы часто хотите, это IN-список переменной длины, и это не поддерживается сразу. Тем не менее, вариант expr IN (subquery) предложения IN вместе с unnesting массива будет работать.

Oracle не поддерживает анонимный тип массива, поэтому вам нужно определить именованный тип массива в базе данных, например,

create type NUM_LIST as table of number(10);

Убедитесь, что ваше соединение является OracleConnection. Используйте функцию table() для удаления вложенного массива. И используйте метод createOracleArray() (поддерживаемый с Oracle 11.2) вместо стандартного метода createArrayOf() (который не поддерживается драйвером JDBC Oracle):

PreparedStatement statement = connection.prepareStatement("select pokemon from pokemonTable where capacity in (select * from table(?))");
Array array = ((OracleConnection)statement.getConnection()).createOracleArray("NUM_LIST", new int[]{1,2,3});
statement.setArray(1, array);
ResultSet rs = statement.executeQuery();

Вы можете альтернативно определить NUM_LIST как varray вместо table. Но тогда вам нужно cast(? as NUM_LIST) внутри функции table().

1 голос
/ 24 марта 2010

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

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

Но указанный в документе запрос должен работать. Я могу сказать это по опыту, по крайней мере, Oracle 10g XE в сочетании с ojdbc14.jar. Я подозреваю, что либо автор документа перепутал вещи, либо это действительно касается другой (более старой?) Версии БД и / или драйвера 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().

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