Как лучше всего использовать вложения PreparedStatements?

У меня есть несколько случаев, когда этот раздел устаревших операторов sql основан на зависимости. Например.

if (x !=null)
{
  SQL = "SELECT z WHERE x > y";
}
else
{
  SQL = "SELECT z WHERE x <= y";
} 

SQL2 = SQL + " JOIN a ON b";

Я создаю PreparedStatements из этого устаревшего кода. Какая здесь лучшая практика. Должен ли я создать PreparedStatement для var SQL и вложить его в SQL2, если должно быть несколько PreparedStatement на основе SQL2 без вложенности или что-то совершенно другое?

Код намного сложнее, чем пример, поскольку переменная SQL повторно используется во многих длинных и сложных запросах SQL.

Обновлено: Дизайн проекта требует использования PreparedStatements, в данный момент у меня нет выбора использовать библиотеки.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
3 062
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Это неправильное использование параметров подготовленного оператора. Параметры могут использоваться только вместо буквального значения в выражении SQL. Не имена таблиц, имена столбцов или другой синтаксис SQL.

Вы можете использовать некоторую библиотеку для построения частей SQL-запроса. Я работал над такой библиотекой на PHP, которая называется Zend_Db_Select.

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

  • Покоробление - это небольшая библиотека Java для динамического создания операторов SQL SELECT. [Его] оптимальное место для приложений, которым необходимо создавать сложные запросы с критериями, которые меняются во время выполнения. Обычно выяснение того, как построить эту строку, может быть довольно болезненным. Сквиггл снимает большую часть этой боли.

Это бесплатно и предлагается под лицензией Apache License, которая является довольно гибкой лицензией с открытым исходным кодом.

Поиск в Google по запросу "построитель запросов Java" обнаружил ряд других вариантов, но некоторые из них были платными. Некоторые из них были построителями визуальных запросов, а не построителями программных запросов.

Другой вариант - использовать сложную структуру объектно-реляционного сопоставления, такую ​​как Hibernate, но это кажется излишним для вашей текущей задачи.

Вот похожий вопрос

Короткий ответ - лучшего пути нет. У вас может получиться что-то вроде этого:

String selectQuery =
  (new SelectQuery())
  .addColumns(t1Col1, t1Col2, t2Col1)
  .addJoin(SelectQuery.JoinType.INNER_JOIN, joinOfT1AndT2)
  .addOrderings(t1Col1)
  .validate().toString();

Но мне еще хуже.

Я думаю, с одной стороны, существует пуристский объектный подход, который, вероятно, не будет для вас очень полезным, если вы пытаетесь разобраться в унаследованном коде. Я обнаружил, что при рефакторинге действительно неприятного устаревшего кода, вместо того, чтобы стремиться к «идеальному», часто лучше и проще упрощать небольшие части, как модульные и хорошо документированные, поскольку вы можете создавать их, не переписывая все приложение сразу. Я обнаружил, что самым большим препятствием для меня при рефакторинге плохого кода является то, что если я сделаю слишком большие шаги, я больше не могу быть уверен, что ничего не сломал - если все так плохо, то, вероятно, нет модульных тестов, и, вероятно, есть неопределенное или недокументированное поведение.

Я бы по крайней мере сломал логику и sql в качестве первого прохода. То, что вам не нужно, выглядит примерно так:

String sql = "yadda yadda yadda ? yadda yadda WHERE ";
if (mystery condition 1){
   sql = sql + " page=?"
}
else if (mystery condition 2)
{
 sql = sql + " ORDER BY ? "
}

Через некоторое время вы не сможете сказать, какие утверждения строятся. Не стоит экономить на дублировании исходного sql. Это может быть проще понять как:

private static final String FIND_PAGE_QUERY = "...."
private static final String ORDER_BY_QUERY  = " ..."

if (mystery condition 1){
   return process(FIND_PAGE_QUERY, parameters);
}
else if (mystery condition 2)
{
  return process(ORDER_BY_QUERY, parameters);
}

а затем просто создайте что-нибудь, чтобы обернуть ваши запросы и параметры, передаваемые как Spring JDBC Row Mappers или что-то подобное. Это все еще некрасиво, но это легко сделать в качестве дополнительного шага по сравнению с тем, что у вас есть, и, по крайней мере, разрешит некоторые проблемы с генерацией запросов.

Ибатис очень хорош в этом.

<select id = "queryName" parameterClass = "com.blah.X"><!<[CDATA[
  SELECT z
  FROM a
  JOIN b ON a.id = b.foreign_key
  WHERE

  <isNotNull property = "value">
    x > y
  </isNotNull>

  <isNull property = "value">
    x <= y
  </isNull>

]]></select>

Это лишь небольшая часть того, на что способен Ибатис, но он чрезвычайно легкий. Отличная технология.

Посмотрел Ибатиса, выглядит неплохо, но не по дизайну. Спасибо за ваш вклад. +1

WolfmanDragon 23.12.2008 01:50
Ответ принят как подходящий

> Должен ли я создать PreparedStatement для var SQL и вложить его в SQL2

Нет

> Или должно быть несколько PreparedStatements на основе SQL2 без вложенности

да

Более того: если бы вы могли создать одну строку для каждого запроса, это было бы лучше. Мне не очень нравится смешивать SQL с кодом. Это затрудняет отладку и понимание, вы не можете скопировать / вставить в инструмент SQL, чтобы легко его протестировать. Отделяя SQL от кода, вы изолируете свой запрос от операции (фактической выборки), и его будет легче поддерживать. К тому же, если код не ваш, его будет намного легче понять.

Неважно, похоже, что вы повторяете строки, суть в том, чтобы максимально упростить инструкции.

Я бы сделал что-то вроде этого:

final class DatabaseQueries {
    public final static String SOME_SCENARIO       = "SELECT z WHERE x > y JOIN A, B ";
    public final static String SOME_OTHER_SCENARIO = "SELECT z WHERE x <= y JOIN A, B";
 }

А затем используйте его из своего класса:

 PreparedStatement pstmt = getCon().prepareStatement( getQuery() );


 private String getQuery() { 
     if ( x != null ) { 
          return DatabaseQueries.SOME_SCENARIO;
     } else { 
           return DatabaseQueries.SOME_OTHER_SCENARIO;
     }
 }

При создании класса «DatabaseQueries» вы обнаружите, что повторяете много строк, я думаю, было бы неплохо заменить некоторую часть другими константами.

final class DataBaseQueries { 
    // this one is private
    private final static String JOIN_A_B = " join A, B ";
    public final static String SOME_SCENARIO       = "SELECT z WHERE x > y " + JOIN_A_B ;
    public final static String SOME_OTHER_SCENARIO = "SELECT z WHERE x <= y " + JOIN_A_B ;

}

Дело здесь в том, чтобы упростить задачу. Это первый шаг. На втором этапе вы можете создать класс для создания действительно действительно сложных запросов, но, вероятно, YAGNI.

Если запросов слишком много, вы можете заменить их, чтобы загрузить их из ResourceBundle, как в этом вопрос

Надеюсь, это поможет.

Другой подход - переместить условное выражение в сам оператор SQL, чтобы вам понадобился только один оператор. Это было бы примерно так:

SELECT z WHERE (? IS NOT NULL AND x > y) OR (? IS NULL AND x <= y)

а затем привяжите соответствующее значение для параметра.

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

Другие вопросы по теме