Программирование на Java - где следует хранить операторы SQL? [закрыто]

107

Где JDBC-совместимое приложение должно хранить свои операторы SQL и почему?

Пока мне удалось выделить эти варианты:

  • Жестко закодированы в бизнес-объектах
  • Встроено в предложения SQLJ
  • Инкапсулировать в отдельные классы, например, объекты доступа к данным
  • Управляемые метаданными (отделите схему объекта от схемы данных - опишите сопоставления между ними в метаданных)
  • Внешние файлы (например, файлы свойств или ресурсов)
  • Хранимые процедуры

Каковы «плюсы» и «против» каждого из них?

Следует ли считать код SQL «кодом» или «метаданными»?

Следует ли использовать хранимые процедуры только для оптимизации производительности или они являются законной абстракцией структуры базы данных?

Является ли производительность ключевым фактором при принятии решения? А как насчет привязки к поставщику ?

Что лучше - слабая связь или тугая и почему?

РЕДАКТИРОВАТЬ: Спасибо всем за ответы - вот резюме:

Управляемые метаданными, то есть объектно-реляционные сопоставления (ORM)

Плюсы:

  • Очень абстрактно - сервер БД можно переключить без изменения модели
  • Широкое распространение - практически стандарт
  • Сокращает количество необходимого SQL
  • Может хранить SQL в файлах ресурсов
  • Производительность (обычно) приемлемая
  • Подход, основанный на метаданных
  • (База данных) независимость от поставщика

Минусы:

  • Скрывает SQL и истинные намерения разработчиков
  • SQL сложно проверить / изменить администратором баз данных
  • SQL может все еще понадобиться в нечетных случаях
  • Может принудительно использовать собственный язык запросов, например HQL
  • Не поддается оптимизации (абстракция)
  • Может не хватать ссылочной целостности
  • Заменители из-за незнания SQL или недостаточной заботы о коде в БД
  • Никогда не соответствовать производительности собственной базы данных (даже если она близка)
  • Код модели очень тесно связан с моделью базы данных

Жестко закодированы / инкапсулированы в слое DAO

Плюсы:

  • SQL хранится в объектах, которые обращаются к данным (инкапсуляция)
  • SQL легко писать (скорость разработки)
  • SQL легко отследить, когда требуются изменения
  • Простое решение (без запутанной архитектуры)

Минусы:

  • SQL не может быть просмотрен / изменен администратором баз данных
  • SQL, скорее всего, станет специфичным для БД
  • SQL может стать трудно поддерживать

Хранимые процедуры

Плюсы:

  • SQL хранится в базе данных (близко к данным)
  • SQL анализируется, компилируется и оптимизируется СУБД
  • SQL легко проверить / изменить
  • Снижает сетевой трафик
  • Повышенная безопасность

Минусы:

  • SQL привязан к базе данных (привязка к поставщику)
  • Код SQL сложнее поддерживать

Внешние файлы (например, файлы свойств или ресурсов)

Плюсы

  • SQL можно изменить без необходимости перекомпоновки приложения
  • Отделяет логику SQL от бизнес-логики приложения
  • Центральный репозиторий всех операторов SQL - проще в обслуживании
  • Легче понять

Минусы:

  • Код SQL может стать не обслуживаемым
  • Сложнее проверить код SQL на наличие (синтаксических) ошибок

Встроено в предложения SQLJ

Плюсы:

  • Лучшая проверка синтаксиса

Минусы:

  • Слишком тесно связан с Java
  • Производительность ниже, чем у JDBC
  • Отсутствие динамических запросов
  • Не так популярно
Адриан
источник
Хорошие вопросы, но, может быть, слишком много, чтобы ответить на все сразу. Чтобы ответить на все эти вопросы, потребуется несколько страниц, imho: p
NickDK
+1 Хороший вопрос! Вы должны добавить ORM для @ocdecio. Также добавьте «разбросано повсюду в вашем Java-коде» (что я видел и должно быть хуже всего).
Джим Ферранс 02
2
Я категорически не согласен с тем, что «сложнее поддерживать код SQL» в рамках хранимых процедур. В моем XP SQL было легче поддерживать после того, как он попал в базу данных. Отчасти по причине, используемой во внешних файлах (центральный репозиторий всех операторов SQL - проще в обслуживании), плюс параметры легче управлять.
Michael Lloyd Lee mlk
1
На мой взгляд, вы упустили один вариант: использование просмотров. Вы можете выразить сложный SQL в представлениях, а затем просто выразить простые выборки в этих представлениях (используя любой тип абстракции: DAO, SQLJ, ORM и т. Д.). У вас будут те же плюсы, что и у хранимых процедур, но я не думаю, что у вас будут их минусы ...
Лукас Эдер

Ответы:

31

Обычно, чем больше приложение растет с точки зрения размера и / или возможности повторного использования, тем больше возникает потребность во внешнем / абстракционном выражении операторов SQL.

Жесткое программирование (как статические конечные константы) - это первый шаг. Следующий шаг - сохранение в файле (properties / xml file). Управление метаданными (как это делает ORM, например Hibernate / JPA) - это последний шаг.

Жесткий код имеет недостаток, заключающийся в том, что ваш код, вероятно, станет специфичным для БД, и вам нужно переписывать / перестраивать / распространять при каждом изменении. Преимущество в том, что он у вас в одном месте.

Сохранение в файле имеет тот недостаток, что он может стать недоступным для обслуживания по мере роста приложения. Преимущество в том, что вам не нужно переписывать / перестраивать приложение, если вам не нужно добавлять дополнительный метод DAO.

У управляемой метаданными есть недостаток, заключающийся в том, что код вашей модели очень тесно связан с моделью базы данных. Для каждого изменения в модели базы данных вам необходимо переписывать / перестраивать / распространять код. Преимущество состоит в том, что он очень абстрактный и вы можете легко переключиться с сервера БД без необходимости менять свою модель (но спросите себя сейчас: как часто компания будет переключаться с сервера БД? Вероятно, не реже одного раза в 3 года, не так ли? разве это?).

Я не буду называть хранимые процедуры "хорошим" решением этой проблемы. У них совсем другое предназначение. Хотя ваш код будет зависеть от используемой БД / конфигурации.

BalusC
источник
22

Я не знаю, оптимально ли это, но, по моему опыту, они в конечном итоге жестко закодированы (т.е. строковые литералы) на уровне DAO.

облет
источник
5
Возможно, это не оптимально, но я тоже этим занимаюсь. Легко писать, легко отследить и не беспокоиться о беспорядочной архитектуре.
Джеймс Кронен
21
А все время, потраченное на отслеживание жестко запрограммированного SQL, - это безопасность работы. Если вы единственный, кто знает, где находится SQL, вас нельзя уволить.
S.Lott
11
Меня всегда удивляет, что многие люди, которые стараются создать красиво спроектированный, чистый объектно-ориентированный Java-код, - это те же люди, которые терпят написание беспорядочного, неэффективного SQL и просто вставлять его в виде строк в случайных местах. Если ваш SQL - это просто строки на уровне DAO, то я могу гарантировать, что в вашей команде нет администратора баз данных. По крайней мере, плохой администратор базы данных.
Дэниел Прайден
3
-1. Допустимо иметь DAO, но по крайней мере переместите запросы куда-нибудь в файл свойств, чтобы администратор баз данных мог их просмотреть и настроить по мере необходимости!
cethegeek
3
По моему опыту, если вы используете прямой JDBC, размещение строки запроса на уровне объекта доступа к данным, вероятно, является лучшим подходом, если вы не можете использовать решение ORM. Единственное предостережение: убедитесь, что все на одной странице со стандартами кодирования для классов DAO, если вы пойдете по этому пути. Я не работал и с пакетом ресурсов, и с маршрутами хранимых процедур, и оба они были абсолютным кошмаром обслуживания, поскольку он распределяет логику доступа к данным на несколько уровней, поэтому добавление столбца к запросу требует, чтобы вы изменили вещи в разных местах.
Джейсон Гритман 02
12

Я не думаю, что кто-то даст вам подробные сведения за / против, поскольку это довольно большой вопрос. Итак, вот то, что я использовал в прошлом, и то, что я буду использовать в будущем.

Я использую SQL, жестко закодированный в DAL. Я думал, что это нормально, пока администраторы баз данных не захотели поиграть с SQL. Затем вам нужно откопать его, отформатировать и передать администраторам баз данных. Кто над этим посмеется и все заменит. Но без красивых вопросительных знаков или вопросительных знаков в неправильном порядке, и вам придется снова вставить это в код Java.

Мы также использовали ORM, и хотя это здорово для разработчиков, наши администраторы баз данных ненавидели его, так как для них нет SQL, над которым можно было бы посмеяться. Мы также использовали странный ORM (заказной от стороннего поставщика), который имел привычку убивать базу данных. С тех пор я использовал JPA, и это было здорово, но получить что-либо сложное с его использованием после DBA - это битва в гору.

Теперь мы используем хранимые процедуры (с жестко запрограммированным оператором вызова). Теперь первое, на что все будут жаловаться, это то, что вы привязаны к базе данных. Ты. Однако как часто вы меняли базу данных? Я точно знаю, что мы просто не могли даже попробовать это, количество другого кода, зависящее от этого, плюс переподготовка наших администраторов баз данных плюс перенос данных. Это была бы очень дорогая операция. Однако, если в вашем мире требуется срочное изменение баз данных, SP, скорее всего, отсутствуют.

В будущем я хотел бы использовать хранимые процедуры с инструментами генерации кода для создания классов Java из пакетов Oracle.

Изменить 2013-01-31 : несколько лет спустя и администраторы баз данных, и теперь мы используем Hibernate, переходя на SQL (сохраненные процессы в БД) только в случае крайней необходимости. Думаю, это лучшее решение. В 99% случаев базам данных не нужно беспокоиться о SQL, а в 1% случаев они делают это в том месте, где им уже комфортно.

Майкл Ллойд Ли млк
источник
1
+1 за идею написания хранимых процедур, а затем генерации из них кода Java, а не наоборот.
Дэниел Прайден
Я считаю, что слой Java НЕ должен имитировать или отображать каким-либо образом уровень БД. Я думаю, если вы пытаетесь абстрагироваться от пакета Oracle, создайте другой пакет или несколько процедур обертывания. Я пытаюсь логически полностью разделить их на практике.
Jé Queue,
2
@Xepoch: Я действительно согласен - возможно, мне следовало сформулировать свой комментарий иначе. Ваша база данных должна отражать вашу модель данных (модель отношений сущностей), а ваша объектная модель также должна отражать вашу модель данных (хотя и не обязательно идентична). Так что они должны быть как минимум родственными. Что касается генерации кода Java из хранимых процедур, суть в том, что API для доступа к вашей базе данных должен быть производным от структуры вашей модели данных, а не вашей модели данных, производной от структуры ваших объектов.
Дэниел Прайден 02
Возможно, вам будет интересно использовать jooq.org . Он делает именно то, что вы сказали: «генерация кода для создания классов Java из пакетов Oracle». Кроме того, он поставляется с SQL-подобным DSL, похожим на LINQ в C #, если вам нужно выразить SQL на Java, который вы не можете поместить в хранимую процедуру.
Лукас Эдер
10

Надеемся, что при использовании ORM (например, спящего режима) вам не о чем будет беспокоиться о операторах SQL. Производительность обычно приемлемая, и вы также получаете независимость от поставщика.

Отавио Десио
источник
13
-1 у вас будут HQL-операторы, и большая часть проблем останется с HQL. Будут ли они находиться внутри кода (строковые литералы), именованные запросы в аннотациях, именованные запросы в файлах xml, хранящиеся в файлах свойств?
flybywire 02
1
@flybywire - с Hibernate редко приходится прибегать к HQL. В 98% случаев все, что нужно, - это запрос по примерам и критериям (т. Е. С использованием объектов).
SingleShot 02
2
@SingleShot, я не согласен. Если это что-то более сложное, чем выбор по идентификатору, я думаю, что это делается с помощью HQL. Я бы сказал, что критерии и примеры используются при поиске через пользовательский интерфейс, как на экране поиска в каталоге библиотеки. Но посмотрим, что думают другие.
flybywire 02
3
@SingleShot - Я очень не согласен. Мы много используем HQL, особенно для отчетов по запросам. Некоторые функции HQL вообще не поддерживаются критериями (с использованием пользовательских функций SQL, конструкторов в предложении select). QBE иногда может привести к большему количеству проблем, чем решить.
javashlook 02
4
«В Hibernate - большая редкость, чтобы прибегнуть к HQL» - это, безусловно, самая забавная вещь, которую я слышал сегодня. QBE смешно; и хотя вам, возможно, придется прибегнуть к критериям для запросов пользовательского интерфейса, четко определенные запросы (отчеты / взаимодействие с сервисами и т. д.) должны быть в HQL.
ChssPly76 02
10

Следует ли считать код SQL «кодом» или «метаданными»?

Код.

Следует ли использовать хранимые процедуры только для оптимизации производительности или они являются законной абстракцией структуры базы данных?

Хранимые процедуры допускают повторное использование, в том числе внутри других хранимых процедур. Это означает, что вы можете совершить одно обращение к базе данных и заставить ее выполнять вспомогательные инструкции - в идеале наименьший объем трафика. ORM или sproc, время на проводе, идущем к db & back, - это то, что вы не можете окупить.

ORM не поддается оптимизации из-за своей абстракции. IME, ORM также означает отсутствие ссылочной целостности, что затрудняет создание отчетов по базе данных. То, что было сохранено в сложности, теперь увеличилось, чтобы можно было получать данные в работоспособном виде.

Является ли производительность ключевым фактором при принятии решения? А как насчет привязки к поставщику?

Нет, простота есть. Блокировка поставщика также происходит с базой данных - SQL относительно стандартизирован, но все еще существуют способы, специфичные для поставщика.

OMG Пони
источник
4
+1 для вызова кода SQL. Слишком много инструментов ORM пытаются скрыть SQL, хотя на самом деле часто это лучший язык для выражения того, что вы пытаетесь сделать. И я согласен с вашим мнением, что хранимые процедуры лучше ORM, хотя я сомневаюсь, что это будет популярное мнение здесь.
Дэниел Прайден
9

Страх перед привязкой к поставщику в мире Java интересен.

Я надеюсь, что вы не заплатили 50000 долларов за ЦП за Oracle Enterprise, а затем использовали только наименьший общий знаменатель, чтобы в любую минуту переключиться на Mysql. Любой хороший администратор баз данных скажет вам, что между разными широко известными базами данных есть тонкие различия, особенно в отношении моделей блокировки и того, как они обеспечивают согласованность.

Итак, не принимайте решение о том, как реализовать ваши SQL-вызовы, только на основе принципа независимого от поставщика SQL - имейте для этого реальную (деловую) причину.

курочки
источник
1
О, ничего подобного! Основная проблема заключается в том, чтобы позволить группе поддержки изменять операторы SQL (например, для настройки, задач, связанных с администратором баз данных) и улучшать видимость того, что делает приложение (в отношении базы данных. У группы поддержки нет ноу-хау Java, и они не будут с удовольствием загляните в код. Приложение станет новым дополнением к большому количеству существующих приложений, использующих базу данных Ingres.
Адриан,
6

SQL внутри хранимых процедур оптимизируется системой баз данных и компилируется для обеспечения скорости - это его естественный дом. SQL понимается системой баз данных, анализируется системой баз данных. По возможности сохраните свой SQL в базе данных; оберните его в хранимые процедуры или функции или любые единицы логики, которые предоставляет система баз данных, и сделайте простые вызовы, используя любой из инструментов, упомянутых вами или кем-либо еще.

Зачем хранить код SQL для системы баз данных вне базы данных? Часто для скорости разработки. Зачем использовать ORM-отображение? - Некоторые говорят, что отображение ORM обеспечивает совместимость с различными системами баз данных; однако редко в реальном мире приложение когда-либо отходит от платформы базы данных после того, как оно было построено, особенно когда оно начинает использовать расширенные функции, такие как репликация, и в редких случаях бывает, что система базы данных заменяется, некоторая работа оправдана . Я считаю, что одним из недостатков ORM он часто заменяет недостаток знаний SQL или недостаточное внимание к кодированию в базе данных. Кроме того, ORM никогда не будет соответствовать производительности собственной базы данных, даже если она близка.

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

Джон К.
источник
+1 Хорошая точка зрения. Думаю, вам будет интересен этот пост в блоге: database-programmer.blogspot.com/2010/12/… .
Лукас Эдер
5

Единственный вопрос, на который вы задаете однозначный ответ, - это «Код SQL или метаданные?» Это определенно код, и поэтому он должен храниться в каком-то элементе управления исходным кодом и иметь систему для простого обновления до последней версии и отката, когда нет , если что - то пойдет не так.

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

  • ORM - это сокращает количество SQL, которое вам нужно написать, и обрабатывает множество деталей за вас. Вам нужно будет сделать некоторый собственный SQL. Убедитесь, что у вас есть ORM, который изящно справляется с этим.
  • Объекты доступа к данным - сохраните SQL в объектах, которые обращаются к данным. Это инкапсулирует вашу базу данных и делает так, чтобы остальной части вашего приложения не нужно было знать о базовой структуре БД, а только об интерфейсе к этим объектам.
  • Хранимые процедуры - это сохраняет весь ваш SQL в вашей базе данных и позволяет администраторам баз данных легко узнать, что происходит. Все, что вам нужно сделать, это заставить ваш код вызывать сохраненные процедуры
Кенни Дробнак
источник
4

Нам довелось использовать преобразователь SQL iBatis, который ближе к металлу, чем ORM, например Hibernate. В iBatis вы помещаете операторы SQL в файлы ресурсов (XML), которые должны находиться в пути к классам.

Ваш список подходов кажется довольно полным, если вы добавите опцию ORM @ ocdecio. Я бы сказал, что использование ORM и использование сопоставителя SQL и файлов ресурсов - два лучших подхода. Я бы держался подальше от SQLJ, который не получил большого распространения и слишком тесно связывает вас с Java. Также держитесь подальше от хранимых процедур, поскольку они привязывают вас к конкретному поставщику базы данных (стандарты для хранимых процедур практически отсутствуют).

Джим Ферранс
источник
4

Как и большинство из нас, я видел весь спектр, но нам нужно рассматривать SQL как первоклассный язык. Я даже видел, как SQL хранится в БД, который удаляется, а затем выполняется обратно.

Самые успешные системы, которые я видел, используют хранимые процедуры, функции и представления.

Сохраненные процедуры сохраняют текст SQL обратно в БД и позволяют относительно немедленное изменение с помощью РАЗВЕРТЫВАНИЯ и НАСТРОЙКИ (что требует большого количества правильного дизайна для его поддержки).

Все прогнозы должны быть через представления и простые выборки по тем же причинам, вся логика проектирования должна содержаться в представлении.

Jé Queue
источник
+1 за упоминание просмотров. Это еще не отражено в кратком изложении вопроса
Лукас Эдер
2

Я предлагаю использовать DAO с заводской компоновкой. Итак, вам понадобятся следующие примеры объектов:

public class CoolBusinessObject
public class DAOFactory.java
public implementation CoolBusinessOjectDAO
public class CoolBusinessOjectDAOOracleImpl implements CoolBusinessOjectDAO

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

Джей
источник
2

Между этими тремя нет существенной разницы:

  1. Жестко закодированы в бизнес-объектах
  2. Встроен в SQLJпредложения
  3. Инкапсулировать в отдельные классы, например, объекты доступа к данным

Я предполагаю, что вы собираетесь встроить код SQL в строковой форме непосредственно в свой код Java. Хотя 1 и 3, вероятно, будут использовать JDBC напрямую (или какой-либо инструмент, например Apache DbUtils ), 2 добавляет технологию препроцессора в стек, генерируя соответствующий код JDBC перед компиляцией.

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

  • JPA Criteria API , моделирование JPQL как внутреннего предметно-ориентированного языка в Java
  • jOOQ , моделирование SQL как внутреннего предметно-ориентированного языка в Java

Также могут быть другие инструменты, которые помогут вам встраивать SQL в Java более безопасным способом, чем через SQLJ или посредством фактической конкатенации строк.

Лукас Эдер
источник
1

Судя по моему опыту, жесткое кодирование операторов sql в объектах DAO широко используется, хотя я считаю, что это наименее предпочтительный метод. Лучше всего хранить инструкции sql в файле свойств. И получите операторы в объекте DAO через интерфейс к файлам свойств, скажем java.util.Properties . Операторы sql могут перемежаться знаками '?' Для передачи параметров в рамках подхода с использованием подготовленных операторов .

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

Машина
источник
Некоторые люди могут возразить, что это приведет к риску внедрения SQL-кода. Что ты думаешь об этом?
Адриан
2
Если вы все равно храните код SQL вне приложения, в чем преимущество его хранения в виде строк по сравнению с хранением на уровне базы данных (в виде хранимых процедур)? Хранимые процедуры могут более эффективно использовать оптимизатор вашей базы данных, поэтому они почти всегда будут превосходить подготовленные операторы.
Дэниел Прайден
1
Привет, Даниэль, я не имел в виду, что вы не пишете sql procs, я просто имел в виду, что вы вызываете сохраненные процедуры, как я уже упоминал. Это поможет вам лучше контролировать передачу параметров в сохраненную процедуру.
The Machine,
1

Мои попадают в пакеты ресурсов. Я знаю, что это ненормально, но мне и всем "кроме меня" легче всего поддерживать его. Все просто и логично.

Мне вообще любопытно посмотреть, использует ли кто-нибудь мой подход.

Бретт Райан
источник
Любопытно, почему бы вам не сохранить SQL в БД?
Jé Queue
@Xepoch - Что ты имеешь в виду? Операторы находятся в пакетах ресурсов (файлах свойств), которые находятся в том же пакете, что и сущности, поэтому customer.properties относится к Customer.class. Данные хранятся в БД.
Бретт Райан
1

Поскольку rexem написал, что SQL-состояния являются кодом - они должны рассматриваться как код, а не извлекаться извне (если у вас нет веской причины), а помещаться в код, который обрабатывает данные SQL из / в эти операторы. Сегодняшние фреймворки ORM / iBatis предлагают множество упрощений для повседневной разработки JDBC.

Некоторые ответы на ваш вопрос вы найдете в этом вопросе :) Проблема того, как будут храниться ваши SQL-данные, зависит от вашего приложения. Что вам нужно? Высокая безопасность, простота написания кода или обслуживания, кроссплатформенность или привязка к поставщику? Следующий вопрос: нужен ли вам чистый SQL или ORM-фреймворк?

* Hardcoded in business objects
* Encapsulate in separate classes e.g. Data Access Objects

Самое простое решение (P), сложное в обслуживании (C)

* Embedded in SQLJ clauses

Лучшая проверка синтаксиса (P), отсутствие динамических запросов (C), более низкая производительность, чем JDBC (C), не такая популярная (C)

* Metadata driven (decouple the object schema from the data schema - describe the mappings between them in metadata)

Это должен быть конкретный случай, когда вы должны это сделать (C) или, если вы имеете в виду ORM (P);)

* External files (e.g. Properties or Resource files)

Легко обслуживать (P), но сложнее проверить на наличие ошибок (C)

* Stored Procedures

Высокая безопасность (P), код, который трудно решить, проблемы привязки к поставщику (C)

cetnar
источник