Програмування Java - Де слід зберігати оператори SQL? [зачинено]


107

Де JDBC-сумісний додаток повинен зберігати свої SQL-заяви і чому?

Поки мені вдалося визначити такі варіанти:

  • Твердо кодований у бізнес-об'єктах
  • Вбудований у пропозиції SQLJ
  • Інкапсулюйте в окремі класи, наприклад, Об'єкти доступу до даних
  • Метадані, що керуються (від'єднайте об'єктну схему від схеми даних - опишіть відображення між ними у метаданих)
  • Зовнішні файли (наприклад, властивості або файли ресурсів)
  • Збережені процедури

Які "плюси" та "мінуси" для кожного з них?

Чи слід вважати SQL-кодом «код» або «метадані»?

Чи слід використовувати збережені процедури лише для оптимізації продуктивності або вони є законною абстракцією структури бази даних?

Чи вирішальність є ключовим фактором рішення? А як щодо блокування постачальників ?

Що краще - нещільна муфта або герметична муфта і чому?

ВЕДЕНО: Дякую всім за відповіді - ось короткий опис:

Метадані, тобто реляційні відображення об'єктів (ORM)

Плюси:

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

Мінуси:

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

Твердо кодований / інкапсульований у шарі DAO

Плюси:

  • SQL зберігається в об'єктах, які отримують доступ до даних (інкапсуляція)
  • SQL легко записати (швидкість розвитку)
  • SQL легко відстежити, коли потрібні зміни
  • Просте рішення (без брудної архітектури)

Мінуси:

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

Збережені процедури

Плюси:

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

Мінуси:

  • SQL прив’язаний до бази даних (блокування постачальника)
  • SQL-код важче підтримувати

Зовнішні файли (наприклад, властивості або файли ресурсів)

Плюси

  • SQL можна змінити без необхідності перебудови програми
  • Розв'язує логіку SQL від логіки бізнесу програми
  • Центральний сховище всіх операторів SQL - простіше в обслуговуванні
  • Легше зрозуміти

Мінуси:

  • Код SQL може стати нездійсненним
  • Важче перевірити SQL-код на наявність (синтаксису) помилок

Вбудований у пропозиції SQLJ

Плюси:

  • Краща перевірка синтаксису

Мінуси:

  • Занадто близько до Яви
  • Нижча продуктивність, ніж JDBC
  • Відсутність динамічних запитів
  • Не така популярна

Хороші запитання, але, можливо, трохи занадто багато, щоб відповісти відразу. Щоб відповісти на всі ці imho, знадобиться кілька сторінок: p
NickDK

+1 Добре запитання! Ви повинні додати "ORM" на @ocdecio. Також додайте "скріплений скрізь у своєму Java-коді" (який я бачив і повинен бути приблизно гіршим).
Джим Ферранс

2
Я не погоджуюся з "SQL-кодом важче підтримувати" в "Збережених процедурах". У моєму XP SQL було легше підтримувати, як тільки він зайшов у базу даних. Частково з причини, яка використовується у зовнішніх файлах (центральний сховище всіх операторів SQL - простіше у обслуговуванні), плюс параметри простіші в управлінні.
Майкл Ллойд Лі mlk

1
На мою думку, ви пропустили один варіант: Використання поглядів. Ви можете висловити складний SQL у видах, а потім просто висловити простий вибір на цих видах (використовуючи будь-який тип абстракції: DAO, SQLJ, ORM тощо). У вас будуть подібні плюси, як і зі збереженими процедурами, але я не думаю, що у вас будуть якісь їхні мінуси ...
Лукаш Едер

Відповіді:


31

Зазвичай, чим більше додаток зростає з точки зору розміру та / або повторного використання, тим більше потребує екстерналізації / абстракціонування операторів SQL.

Жорсткий код (як статичні кінцеві константи) - перший крок. Наступний крок - збереження у файлі (властивості / XML-файл). Метадані (як це зроблено ORM як Hibernate / JPA) є останнім кроком.

Недоліком жорсткого коду є те, що ваш код, ймовірно, стане специфічним для БД і що вам потрібно перезаписувати / перебудовувати / перерозподіляти під час кожної зміни. Перевага полягає в тому, що ви маєте його на 1 місці.

Зберігається у файлі недолік, що він може стати нездійсненним, коли програма зростає. Перевага полягає в тому, що вам не потрібно переписувати / перебудовувати додаток, якщо тільки вам не потрібно додати додатковий метод DAO.

Недоліком керованих метаданих є те, що код вашої моделі дуже щільно поєднаний з моделлю бази даних. Для кожної зміни моделі бази даних вам потрібно буде переписати / відновити / перерозподілити код. Перевагою є те, що це дуже абстрактно і що ви можете легко переходити з сервера БД без необхідності змінювати свою модель (але запитайте себе зараз: як часто компанія переходить з сервера БД? Можливо, принаймні лише раз на 3 роки, чи не так? т це?).

Я не буду називати збережені процедури «хорошим» рішенням для цього. Вони мають зовсім інше призначення. Хоча ваш код залежатиме від використовуваної DB / конфігурації.


21

Я не знаю, чи оптимально це, але в моєму досвіді вони закінчуються жорстким кодом (тобто String literals) у шарі DAO.


5
Це, мабуть, не оптимально, але це те, що я і роблю. Легко писати, легко відстежувати та без брудної архітектури турбуватися.
Джеймс Кронен

21
І весь час, витрачений на відстеження жорсткого коду SQL, - це безпека роботи. Якщо ви єдиний, хто знає, де знаходиться SQL, вас не можуть звільнити.
S.Lott

11
Мене завжди вражає те, що багато людей, які дбають про створення красиво архітектурного, чистого коду OO Java - ті самі люди, які терплять писати безладно, неефективно SQL і просто приклеюють його як рядки у випадкових місцях. Якщо ваш SQL - це лише рядки у вашому шарі DAO, я можу гарантувати, що у вашій команді немає DBA. Принаймні, не хороший DBA.
Даніель Приден

3
-1. Добре мати DAO, але, принаймні, перемістити запити до файлу властивостей кудись, щоб DBA змогла переглянути та налаштувати їх у відповідних випадках!
cethegeek

3
Мій досвід полягав у тому, що якщо ви робите прямо JDBC, введення рядка запиту в рівень об'єкта доступу до даних - це, мабуть, найкращий підхід, якщо ви не можете використовувати рішення ORM. Колись застереження - переконайтесь, що всі на одній сторінці мають стандарти кодування для класів DAO, якщо ви йдете цим шляхом. Я знижував і пакет ресурсів, і маршрути збережених процедур, і обидва були абсолютними кошмарами технічного обслуговування, оскільки він розповсюджує логіку доступу до даних по декількох шарах, тому додавання стовпця до запиту вимагає змінити речі в різних місцях.
Джейсон Грітман

12

Я не думаю, що ніхто не дасть тобі про / кон ламати, що ти хочеш, оскільки це досить велике питання. Тож натомість тут є те, що я використовував у минулому, і що я буду використовувати вперед.

Я використовую SQL з жорстким кодом у DAL. Я вважав, що це добре, поки DBA не захотіли грати з SQL. Тоді вам доведеться викопати його, відформатувати і запустити його до DBA. Хто з цього посміється і замінить все. Але без приємних знаків запитання чи знаків запитання в неправильному порядку, і ви не зможете залишити його назад у коді Java.

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

Зараз ми використовуємо Збережені процедури (з твердим кодом заяви виклику). Тепер перше, на що всі скаржаться, це те, що ви прив’язані до бази даних. Ти є. Однак як часто ви змінювали базу даних? Я знаю на той факт, що ми просто не могли навіть спробувати його, кількість іншого коду, залежного від нього, плюс перекваліфікація наших DBA та міграція даних. Це була б дуже дорога операція. Однак якщо у вашому світі потрібні зміни БД на краплі капелюха, то SP-то, ймовірно, не будуть.

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

Редагувати 2013-01-31 : Через кілька років та DBA пізніше, і ми використовуємо Hibernate, переходячи до SQL (зберігаються програми в БД) лише за необхідності. Це я вважаю найкращим рішенням. У 99% випадків БД не потребують турбуватися про SQL, а 1%, які вони роблять, це в тому місці, в якому вони вже комфортні.


1
+1 для ідеї написання збережених процедур, а потім генерування Java-коду з них, а не навпаки.
Даніель Приден

Я вважаю, що шар Java НЕ повинен імітувати або перетворювати жодним чином шар DB. Я думаю, якщо ви намагаєтесь абстрагувати пакет Oracle, то зробіть ще один пакет або більше процедур обгортання. Я намагаюсь і логічно повністю розділити ці два на практиці.
Черга Jé

2
@Xepoch: Я дійсно згоден - можливо, я мав би сформулювати свій коментар по-іншому. Ваша база даних повинна відображати вашу модель даних (модель відносин з сутністю), а ваша об'єктна модель також повинна бути відображенням вашої моделі даних (хоча не обов'язково ідентична). Тож вони повинні бути принаймні пов’язані. Що стосується генерування коду Java із збережених процедур, справа полягає в тому, що API доступу до вашої бази даних повинен виходити зі структури вашої моделі даних, а не ваша модель даних, яка походить із структури ваших об'єктів.
Даніель Приден

Можливо, вам буде цікаво використовувати jooq.org . Це робить саме те, що ви сказали: "генерація коду для створення класів Java з пакетів Oracle". Крім цього, він постачається з SQL-подібним DSL, подібним до LINQ в C #, якщо вам потрібно виразити SQL в Java, який ви не можете помістити всередині збереженої процедури.
Лукас Едер

10

При використанні ОРЗ (наприклад, сплячий режим) , ви , сподіваюся , не матиме ні одного заяви SQL турбуватися. Продуктивність зазвичай прийнятна, і ви також отримуєте незалежність від постачальника.


13
-1 у вас будуть заяви HQL, і більшість проблем залишаються щодо HQL. Чи будуть вони знаходитися всередині коду (рядкові літерали), названих запитами в анотаціях, іменованими запитами у файлах xml, що зберігаються у файлах властивостей?
flybywire

1
@flybywire - у сплячому режимі рідкість вдаватися до HQL. У 98% випадків потрібне запит за прикладом та за критеріями (тобто з використанням об’єктів).
SingleShot

2
@SingleShot, я не згоден. Якщо це щось складніше, ніж select by id, я думаю, що це робиться з HQL. Я б сказав, що критерії та приклад використовуються при пошуку, керованому користувальницьким інтерфейсом, як на екрані пошуку в каталозі бібліотеки. Але давайте подивимось, що думають інші.
flybywire

3
@SingleShot - я дуже не згоден. Ми використовуємо багато HQL, особливо для запитів звітування. Деякі функції HQL взагалі не підтримуються критеріями (з використанням користувацьких функцій SQL, конструкторів у пункті вибору). QBE іноді може призвести до більшої кількості проблем, а потім вирішує.
javashlook

4
"З сплячим режимом - рідкість вдаватися до HQL" - це, безумовно, найсмішніше, що я чув сьогодні. QBE смішно; і хоча вам, можливо, доведеться вдатися до Критеріїв для запитів у користувальницькому інтерфейсі, все чітко визначені запити (взаємодія з повідомленнями / службою / тощо) повинні бути в HQL.
ChssPly76

10

Чи слід вважати SQL-кодом «код» або «метадані»?

Код.

Чи слід використовувати збережені процедури лише для оптимізації продуктивності або вони є законною абстракцією структури бази даних?

Збережені процедури дозволяють повторно використовувати, включаючи всередині інших збережених процедур. Це означає, що ви можете здійснити одну поїздку до бази даних та запропонувати їй виконувати допоміжні інструкції - найменший обсяг трафіку ідеальний. ОРМ або проросток, час, що йде на провід, повертається на точило і назад - те, що ви не можете відшкодувати.

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

Чи вирішальність є ключовим фактором рішення? А як щодо блокування постачальників?

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


4
+1 для виклику коду SQL. Занадто багато інструментів ORM намагаються приховати SQL, оскільки насправді це найкраща мова для вираження того, що ви намагаєтеся зробити. І я погоджуюся з вашою думкою, що зберігаються процедури кращі, ніж ORM, хоча я сумніваюся, що тут буде популярна думка.
Даніель Приден

9

Страх перед замиканням постачальників у світі Java цікавий.

Я сподіваюся, що ви не заплатили CPU в розмірі 50000 доларів за Oracle Enterprise, а потім використали лише найменший розповсюджений знаменник для того, щоб перейти на Mysql будь-яку хвилину. Як вам скаже будь-яка хороша DBA, між різними базами великих імен існують тонкі відмінності, особливо що стосується моделей блокування та того, як вони досягають узгодженості.

Отже, не приймайте рішення про те, як реалізовувати свої SQL-дзвінки лише на основі принципу агностичного SQL постачальника - у цього є реальна (ділова) причина.


1
О, нічого подібного! Основна проблема - дозволити команді підтримки змінювати заяви SQL (наприклад, для налаштування завдань, пов’язаних з DBA) та покращувати видимість того, що робить додаток (стосовно бази даних. Команда підтримки не має ноу-хау на Java, і вони не будуть з радістю перегляньте детальну інформацію про додаток. Додаток стане новим доповненням до великої кількості існуючих, які використовують усі бази даних Інгреса.
Адріан,

6

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

Навіщо зберігати SQL-код для системи бази даних поза db? Часто для швидкості розвитку. Навіщо використовувати картування ORM? - Деякі кажуть, що картотека ORM забезпечує сумісність для різних систем баз даних; однак рідко в реальному світі програма ніколи не відходить від платформи бази даних, коли вона була побудована, особливо коли вона починає використовувати такі розширені функції, як реплікація, і за рідкісних випадків трапляється, що система бази даних замінена, деяка робота гарантована . Я вважаю, один з недоліків ORM, який часто замінює відсутність знань SQL або відсутність уважності для кодування в db. Також ORM ніколи не буде відповідати продуктивності бази даних, навіть якщо вона наближається.

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


+1 Приємна точка зору. Ви будете зацікавлені в цьому блозі, я думаю: database-programmer.blogspot.com/2010/12 / ... .
Лукас Едер

5

Єдине запитання, на яке ви маєте певну відповідь, - це "SQL-код або метадані?" Це, безумовно, код і як такий повинен зберігатися в якомусь контролі вихідного коду і мати систему для легкого оновлення до останньої версії та відкочування, якщо не, якщо все піде не так.

Я бачив три способи роботи з SQL в додатку, і кожен має свої плюси і мінуси. Не існує найкращого способу, але найкраще - просто вибрати той, який добре працює з вашою заявкою, і дотримуйтесь її.

  • ORM - це скорочує кількість SQL, який потрібно написати, і обробляє безліч деталей для вас. Вам потрібно буде виконати кілька спеціальних SQL. Переконайтеся, що у вас є ОРМ, який обробляє це витончено.
  • Об'єкти доступу до даних - зберігайте SQL в об'єктах, які отримують доступ до даних. Це інкапсулює вашу базу даних і робить її так, що решта вашої програми не повинна знати про базову структуру БД, просто про інтерфейс до цих об'єктів.
  • Збережені процедури - це зберігає весь ваш SQL у вашій базі даних та полегшує дізнатися, що відбувається вашим DBA. Все, що вам потрібно зробити - це зателефонувати на код, що зберігається

4

Ми, звичайно, використовуємо iBatis SQL-mapper, який ближче до металу, ніж ORM, як Hibernate. В iBatis ви ставите оператори SQL у файли ресурсів (XML), які повинні бути у класі.

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


4

Як і більшість із нас, я бачив цілий гаммут, але нам потрібно вважати SQL мовою першого класу. Я навіть бачив SQL, що зберігається в БД, який знімається та виконується назад.

У найуспішніших системах, які я бачив, використовуються збережені процедури, функції та представлення.

Збережені програми підтримують повернення тексту SQL у БД і дозволяють відносно негайно змінитись тими, хто ЗАБЕЗПЕЧУЄТЬСЯ та НАСТРОЮЄ (що вимагає багато належного дизайну для його підтримки).

Усі проекції повинні здійснюватися за допомогою представлень і просто вибирати з тих же причин, вся логіка проекції повинна міститися в представленні.


+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, ви можете також використовувати будь-яку з цих технологій:

  • API критеріїв JPA , що моделює 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, я просто мав на увазі, ти називаєш збережені програми, до речі, я згадав. Це допомагає вам мати кращий контроль над передачею параметрів до збереженого процесора.
Машина

1

Шахта закінчується в пакетів ресурсів. Я знаю, що це не нормально, але це простіше для мене і будь-кого, хто не є мені. Це прямо і логічно.

Мені справді цікаво побачити, чи хтось також використовує мій підхід.


Цікаво, чому ти не збережеш SQL у БД?
Черга Jé

@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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.