Исключение нулевого указателя генерируется, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:
null
. null
. null
, как если бы это был массив. null
, как если бы это был массив. null
как будто это было значение Throwable. Приложения должны бросать экземпляры этого класса, чтобы указать на другие незаконные использования объекта null
.
Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
Анализ доступных различных вариантов, и за и против каждого доступен здесь .
предложенные опции:
SELECT my_column FROM my_table WHERE search_column = ?
, выполняют его для каждого значения и ОБЪЕДИНЕНИЯ клиентские результаты. Требует только одного подготовленного оператора. Медленный и болезненный. SELECT my_column FROM my_table WHERE search_column IN (?,?,?)
и выполняют его. Требует, чтобы тот подготовил оператор на size-of-IN-list. Быстрый и очевидный. SELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ...
и выполняют его. [Или используйте UNION ALL
вместо тех точек с запятой. - редактор] Требует, чтобы тот подготовил оператор на size-of-IN-list. Глупо медленный, строго хуже, чем WHERE search_column IN (?,?,?)
, таким образом, я не знаю, почему блоггер даже предложил его. SELECT my_column FROM my_table WHERE search_column IN (1,2,3,4,5,6,6,6,6,6)
. Любой достойный сервер оптимизирует дублирующиеся значения прежде, чем выполнить запрос. Ни одна из этих опций не является супер большой, все же.
на Дублирующиеся вопросы ответили в этих местах с одинаково нормальными альтернативами, тем не менее ни один из них супер большой:
Правильный Ответ при использовании JDBC4 и сервера, который поддерживает x = ANY(y)
, должен использовать PreparedStatement.setArray
, как описано здесь:
, кажется, нет никакого способа сделать setArray
работа с В СПИСКАХ, все же.
Иногда SQL-операторы загружаются во времени выполнения (например, из файла свойств), но требуют переменного количества параметров. В таких случаях сначала определите запрос:
query=SELECT * FROM table t WHERE t.column IN (?)
Затем, загружают запрос. Тогда определите количество параметров до выполнения его. Как только количество параметра известно, выполняется:
sql = any( sql, count );
, Например:
/**
* Converts a SQL statement containing exactly one IN clause to an IN clause
* using multiple comma-delimited parameters.
*
* @param sql The SQL statement string with one IN clause.
* @param params The number of parameters the SQL statement requires.
* @return The SQL statement with (?) replaced with multiple parameter
* placeholders.
*/
public static String any(String sql, final int params) {
// Create a comma-delimited list based on the number of parameters.
final StringBuilder sb = new StringBuilder(
new String(new char[params]).replace("\0", "?,")
);
// Remove trailing comma.
sb.setLength(Math.max(sb.length() - 1, 0));
// For more than 1 parameter, replace the single parameter with
// multiple parameter placeholders.
if (sb.length() > 1) {
sql = sql.replace("(?)", "(" + sb + ")");
}
// Return the modified comma-delimited list of parameters.
return sql;
}
Для определенных баз данных, где передача массива через спецификацию JDBC 4 не поддерживается, этот метод может упростить преобразование медленного = ?
в быстрее IN (?)
условие пункта, которое может тогда быть расширено путем вызова any
метод.
Идея следующего Adam. Сделайте свой подготовленный вид оператора выбора my_column от my_table, где search_column в (#) Создают Строку x и заполняют его многими"???" в зависимости от Вашего списка значений Тогда просто изменяют # в запросе для Вашей новой Строки x заполнение
Только для полноты: Пока набор значений не является слишком большим, Вы могли также просто строковая конструкция оператор как
... WHERE tab.col = ? OR tab.col = ? OR tab.col = ?
, который Вы могли тогда передать, чтобы подготовиться (), и затем использовать setXXX () в цикле для устанавливания всех значений. Это смотрит yucky, но много "больших" коммерческих систем обычно делают такого рода вещь, пока они не поражают определенные для DB пределы, такие как 32 КБ (я думаю, что это) для операторов в Oracle.
, Конечно, необходимо удостовериться, что набор никогда не будет необоснованно большим, или делать обнаружение ошибок, если это.
Никаким простым путем AFAIK. Если цель должна поддержать отношение кэша оператора на высоком уровне (т.е. не создать оператор на каждое количество параметра), можно сделать следующее:
создают оператор с некоторыми (например, 10) параметры:
... ГДЕ В (??????????)...
Связывают все фактические параметры
setString (1, "нечто"); setString (2, "панель");
Связывают остальных как ПУСТОЙ УКАЗАТЕЛЬ
setNull (3, Типы. VARCHAR)... setNull (10, Типы. VARCHAR)
ПУСТОЙ УКАЗАТЕЛЬ никогда ничему не соответствует, таким образом, это оптимизировано планом SQL разработчик.
логику легко автоматизировать при передаче Списка в функцию ДАО:
while( i < param.size() ) {
ps.setString(i+1,param.get(i));
i++;
}
while( i < MAX_PARAMS ) {
ps.setNull(i+1,Types.VARCHAR);
i++;
}
Неприятное обходное решение, но конечно выполнимый должно использовать вложенный запрос. Составьте временную таблицу MYVALUES со столбцом в нем. Вставьте свой список значений в таблицу MYVALUES. Тогда выполнитесь
select my_column from my_table where search_column in ( SELECT value FROM MYVALUES )
Ужасный, но жизнеспособная альтернатива, если Ваш список значений является очень большим.
Эта техника имеет добавленное преимущество потенциально лучших планов запросов от оптимизатора (проверьте страницу на несколько значений, сканирование таблицы только однажды вместо этого однажды на значение, и т.д.), может экономить наверху, если Ваша база данных не кэширует подготовленные операторы. Ваши "ВСТАВКИ" должны были бы быть сделаны в пакете, и таблица MYVALUES, возможно, должна быть настроена для имения минимальной блокировки или других высоко-служебных мер защиты.
Я никогда не пробовал его, но был бы, .setArray () делают то, что Вы ищете?
Обновление : Очевидно нет. setArray только, кажется, работает с java.sql. Массив, который прибывает из столбца ARRAY, который Вы получили от предыдущего запроса или подзапроса со столбцом ARRAY.
Я предполагаю, что Вы могли (использование основной обработки строк) генерируют строку запроса в PreparedStatement
для имения многих ?
соответствие количеству объектов в списке.
, Конечно, при выполнении этого Вы - просто шаг далеко от генерации гиганта, объединенного в цепочку OR
в Вашем запросе, но не имея правильного количества ?
в строке запроса, я не вижу, как еще можно работать вокруг этого.
попытаться использовать функцию instr?
select my_column from my_table where instr(?, ','||search_column||',') > 0
тогда
ps.setString(1, ",A,B,C,");
По общему признанию это - определенный грязный взлом, но он действительно уменьшает возможности для внедрения SQL. Работы в оракуле так или иначе.
Сгенерируйте строку запроса в Предварительном Составе, чтобы количество ?s совпадало с количеством элементов в вашем списке. Вот пример:
public void myQuery(List<String> items, int other) {
...
String q4in = generateQsForIn(items.size());
String sql = "select * from stuff where foo in ( " + q4in + " ) and bar = ?";
PreparedStatement ps = connection.prepareStatement(sql);
int i = 1;
for (String item : items) {
ps.setString(i++, item);
}
ps.setInt(i++, other);
ResultSet rs = ps.executeQuery();
...
}
private String generateQsForIn(int numQs) {
String items = "";
for (int i = 0; i < numQs; i++) {
if (i != 0) items += ", ";
items += "?";
}
return items;
}