1. Вступ
1.1. Objectifs
PDF цього документа доступний |TYT|.
Приклади з документа доступні за посиланням |TYT|.
У цьому документі ми пропонуємо ознайомитися з основними концепціями збереження даних за допомогою API JPA (Java Persistence API). Прочитавши цей документ і протестувавши наведені в ньому приклади, читач повинен отримати необхідні базові знання, щоб надалі діяти самостійно.
API JPA є відносно новим. Він став доступним лише починаючи з версії JDK 1.5. Рівень JPA має своє місце в багаторівневій архітектурі. Розглянемо таку досить поширену тришарову архітектуру:
![]() |
- шар [1], який тут називається [ui] (User Interface), є шаром, що взаємодіє з користувачем через графічний інтерфейс Swing, консольний інтерфейс або веб-інтерфейс. Її роль полягає в тому, щоб передавати дані, отримані від користувача, на рівень [2] або ж відображати для користувача дані, надані рівнем [2].
- Рівень [2], який тут називається [metier], — це рівень, що застосовує так звані бізнес-правила, c.a.d. специфічна логіка додатка, яка не зважає на те, звідки надходять дані, що їй надаються, і куди надходять результати, які вона генерує.
- шар [3], який тут називається [dao] (Data Access Object), — це шар, який надає шару [2] попередньо записані дані (файли, бази даних, ...) та зберігає деякі результати, надані шаром [2].
- Рівень [JDBC] — це стандартний рівень, що використовується в Java для доступу до баз даних. Його зазвичай називають драйвером JDBC для SGBD.
Було докладено чимало зусиль, щоб полегшити розробникам написання цих різних шарів. Серед них JPA покликаний спростити написання шару [dao], який керує так званими «персистентними» даними, звідки й походить назва API (Java Persistence API). Одним із рішень, яке за останні роки набуло популярності в цій галузі, є Hibernate:
![]() |
Рівень [Hibernate] розташовується між рівнем [dao], написаним розробником, та рівнем [Jdbc]. Hibernate — це ORM (об’єктно-реляційне відображення), інструмент, який слугує мостом між реляційним світом баз даних та світом об’єктів, з якими працює Java. Розробник шару [dao] більше не бачить ні шару [Jdbc], ні таблиць бази даних, вміст яких він хоче використовувати. Він бачить лише об’єктне відображення бази даних, яке надає шар [Hibernate]. Зв’язок між таблицями бази даних та об’єктами, з якими працює рівень [dao], здійснюється переважно двома способами:
- за допомогою конфігураційних файлів типу XML
- за допомогою анотацій Java у коді — ця техніка доступна лише починаючи з версії JDK 1.5
Рівень [Hibernate] є рівнем абстракції, який прагне бути максимально прозорим. Ідеальним варіантом є те, щоб розробник рівня [dao] міг повністю ігнорувати той факт, що він працює з базою даних. Це можливо, якщо саме не він пише конфігурацію, яка слугує мостом між реляційним та об’єктним світами. Налаштування цього мосту є досить складним і вимагає певної практики.
Об’єктний рівень [4], що є відображенням рівня BD, називається «контекстом персистентності». Шар [dao], що базується на Hibernate, виконує операції збереження (CRUD: create — read — update — delete) над об’єктами контексту збереження; ці операції перетворюються Hibernate на команди SQL. Для операцій запиту до бази даних (SQL Select), Hibernate надає розробнику мову HQL (Hibernate Query Language) для запитів до контексту збереження даних [4], а не до самої бази даних BD.
Hibernate є популярним, але складним у освоєнні. Крива навчання, яку часто подають як легку, насправді є досить крутою. Як тільки з’являється база даних із таблицями, що мають відношення «один до багатьох» або «багато до багатьох», налаштування реляційно-об’єктного мосту виходить за межі можливостей звичайного новачка. Помилки в налаштуванні можуть призвести до зниження продуктивності додатків.
У комерційному секторі існував аналог Hibernate під назвою Toplink:
![]() |
З огляду на успіх продуктів ORM компанія Sun, розробник Java, вирішила стандартизувати рівень ORM за допомогою специфікації під назвою JPA, яка з’явилася одночасно з Java 5. Специфікація JPA була реалізована в обох продуктах — Toplink та Hibernate. Toplink, який раніше був комерційним продуктом, відтоді став вільним програмним забезпеченням. З JPA попередня архітектура набуває такого вигляду:
![]() |
Рівень [dao] тепер взаємодіє зі специфікацією JPA — набором інтерфейсів. Розробник отримав переваги у вигляді стандартизації. Раніше, якщо він змінював свій рівень ORM, йому доводилося також змінювати рівень [dao], який був написаний для взаємодії з конкретним ORM. Тепер він напише шар [dao], який взаємодіятиме з шаром JPA. Незалежно від того, який продукт реалізує цей шар, інтерфейс шару JPA, що надається шару [dao], залишається незмінним.
У цьому документі будуть наведені приклади JPA у різних сферах:
- по-перше, ми розглянемо реляційно-об’єктний міст, який будує рівень ORM. Він створюватиметься за допомогою анотацій Java 5 для баз даних, у яких містяться відносини між таблицями типу:
- «один до одного»
- один до багатьох
- багато до багатьох
Щоб проілюструвати цю сферу, ми створимо такі тестові архітектури:
![]() |
Наші тестові програми будуть консольними додатками, які безпосередньо звертатимуться до шару JPA. При цьому ми ознайомимося з основними методами шару JPA. Ми працюватимемо в середовищі, яке називається «Java SE» (Standard Edition). JPA працює як у середовищі Java SE, так і в Java EE5 (Enterprise Edition).
- Коли ми опануємо як налаштування реляційно-об’єктного мосту, так і використання методів шару JPA, ми повернемося до більш класичної багатошарової архітектури:
![]() |
Доступ до шару [JPA] здійснюватиметься через двошарову архітектуру [metier] та [dao]. Для зв’язування цих рівнів між собою буде використовуватися фреймворк Spring [7], а потім контейнер EJB3 з JBoss.
Вище ми зазначали, що JPA доступний у середовищах SE та EE5. Середовище Java EE5 надає численні сервіси у сфері доступу до постійних даних, зокрема пули з’єднань, менеджери транзакцій тощо. Розробнику може бути цікаво скористатися цими сервісами. Java-середовище EE5 поки що не дуже поширене (травень 2007 року). Наразі його можна знайти на сервері додатків Sun Application Server 9.x (Glassfish). Сервер додатків — це, по суті, сервер веб-додатків. Якщо створювати автономний графічний додаток типу Swing, то середовище EE та послуги, які воно надає, недоступні. Це є проблемою. Починають з’являтися «автономні» середовища EE, c.a.d. які можна використовувати поза межами сервера додатків. Це стосується JBos та EJB3, які ми будемо використовувати в цьому документі.
У середовищі EE5 шари реалізовані об’єктами, що називаються EJB (Enterprise Java Bean). У попередніх версіях EE об’єкти EJB (EJB, 2.x) вважалися складними у впровадженні та тестуванні, а іноді й малопродуктивними. Розрізняють «entity» EJB2.x та «session» EJB2.x. Коротко кажучи, EJB2.x «entity» — це відображення рядка таблиці бази даних, а EJB2.x «session» — об’єкт, що використовується для реалізації шарів [metier], [dao] багаторівневої архітектури. Одне з головних зауважень щодо шарів, реалізованих за допомогою EJB, полягає в тому, що їх можна використовувати лише в межах контейнерів EJB — служби, що надається середовищем EE. Це ускладнює проведення модульних тестів. Отже, на наведеному вище схематичному зображенні модульні тести рівнів [metier] та [dao], побудованих на основі EJB, вимагали б розгортання сервера додатків — досить трудомісткої операції, яка не дуже спонукає розробника часто проводити тестування.
Фреймворк Spring з’явився як відповідь на складність EJB2. Spring надає в середовищі SE значну кількість сервісів, які зазвичай забезпечуються середовищами EE. Так, у розділі «Збереження даних», який нас тут цікавить, Spring надає пули з’єднань та менеджери транзакцій, необхідні для додатків. Поява Spring сприяла розвитку культури модульного тестування, яке відразу стало набагато простішим у реалізації. Spring дозволяє реалізовувати рівні додатка за допомогою класичних об’єктів Java (POJO, Plain Old/Ordinary Java Object), що дає змогу повторно використовувати їх в іншому контексті. Нарешті, він досить прозоро інтегрує численні сторонні інструменти, зокрема інструменти збереження даних, такі як Hibernate, Ibatis тощо.
Java EE5 була розроблена для усунення недоліків попередньої специфікації EE. EJB та 2.x стали EJB3. Це POJOs, позначені анотаціями, що роблять їх особливими об’єктами, коли вони знаходяться всередині контейнера EJB3. У цьому контейнері EJB3 зможе користуватися послугами контейнера (пул з’єднань, менеджер транзакцій тощо). Поза контейнером EJB3 об’єкт EJB3 стає звичайним об’єктом Java. Його анотації EJB ігноруються.
Вище ми зобразили Spring та JBoss EJB3 як можливу інфраструктуру (фреймворк) нашої багаторівневої архітектури. Саме ця інфраструктура надаватиме необхідні нам послуги: пул з’єднань та менеджер транзакцій.
- У Spring шари будуть реалізовані за допомогою POJOs. Вони матимуть доступ до сервісів Spring (пул з’єднань, менеджер транзакцій) шляхом ін’єкції залежностей у ці POJOs: під час їх створення Spring ін’єктує в них посилання на сервіси, які їм знадобляться.
-
JBoss EJB3 — це контейнер EJB, який може працювати поза межами сервера додатків. Принцип його роботи (з точки зору розробника) аналогічний тому, що описано для Spring. Ми знайдемо небагато відмінностей.
-
Завершимо цей документ прикладом трирівневого веб-додатку — простим, але типовим:
![]() |
1.2. Références
[ref1]: «Java Persistence with Hibernate», авторства Крістіана Бауера та Гевіна Кінга, видавництво Manning.
[ref1] — це документ, який послужив основою для наведеного нижче матеріалу. Це вичерпна книга обсягом понад 800 сторінок, присвячена використанню Hibernate у двох різних контекстах: з ORM та без нього. Використання Hibernate без JPA, насправді, досі актуальне для розробників, які використовують JDK версії 1.4 або нижче, оскільки JPA з’явився лише у JDK 1.5.
Прочитавши більше трьох чвертей книги та проглянувши решту, я зрозумів, що в цьому документі все є корисним. Досвідчений користувач Hibernate мав би знати майже всю інформацію, наведену на 800 сторінках. Крістіан Бауер та Гевін Кінг виклали матеріал вичерпно, але рідко описували ситуації, з якими ми ніколи не зіткнемося. Все варто прочитати. Книга написана в навчальному стилі: відчувається справжнє прагнення не залишити нічого незрозумілим. Те, що вона написана для використання Hibernate як разом із JPA, так і без нього, створює певні труднощі для тих, хто цікавиться лише однією з цих технологій. Наприклад, автори на численних прикладах описують реляційно-об’єктний міст у обох контекстах. Використовувані концепції дуже близькі, оскільки JPA значною мірою натхненний Hibernate. Однак між ними є деякі відмінності. Тому те, що справедливо для Hibernate, може не відповідати дійсності для JPA, що в підсумку викликає плутанину у читача.
Автори наводять приклади трирівневих додатків у контексті контейнера EJB3. Вони не згадують про Spring. На прикладі ми побачимо, що Spring, однак, простіший у використанні та має більш глобальну спрямованість, ніж контейнер JBoss EJB3, який використовується в [ref1]. Проте «Java Persistence with Hibernate» — це чудова книга, яку я рекомендую всім, хто хоче опанувати основи роботи з ORM.
Використання ORM є складним для початківця.
- Щоб налаштувати реляційно-об’єктний міст, потрібно зрозуміти певні концепції.
- Існує поняття контексту персистентності з відповідними поняттями об’єктів у стані «персистентний», «від’єднаний», «новий»
- існує механізм, пов'язаний із збереженням даних (транзакції, пули з'єднань), як правило, це сервіси, що надаються контейнером
- необхідно виконати налаштування для підвищення продуктивності (кеш другого рівня)
- ...
Ми розглянемо ці поняття на прикладах. Ми не будемо заглиблюватися в теоретичні роздуми щодо них. Наша мета полягає просто в тому, щоб кожного разу дати читачеві змогу зрозуміти приклад і засвоїти його настільки, щоб він міг самостійно вносити в нього зміни або застосувати його в іншому контексті.
1.3. Використані інструменти
У прикладах цього документа використовуються такі інструменти. Деякі з них описано в додатках (завантаження, встановлення, налаштування, використання). У таких випадках вказується номер параграфа та сторінка.
- JDK 1.6 (параграф 5.1)
- IDE для розробки на Java в Eclipse 3.2.2 (параграф 5.2)
- плагін Eclipse WTP (Web Tools Package) (параграф 5.2.3)
- плагін Eclipse SQL Explorer (розділ 5.2.6)
- плагін Eclipse Hibernate Tools (розділ 5.2.5)
- плагін Eclipse TestNG (параграф 5.2.4)
- контейнер сервлетів Tomcat 5.5.23 (параграф 5.3)
- SGBD Firebird 2.1 (розділ 5.4)
- SGBD MySQL5 (розділ 5.5)
- SGBD PosgreSQL (параграф 5.6)
- SGBD Oracle 10g Express (параграф 5.7)
- SGBD SQL Server 2005 Express (параграф 5.8)
- SGBD HSQLDB (параграф 5.9)
- SGBD Apache Derby (параграф 5.10)
- Spring 2.1 (параграф 5.11)
- контейнер EJB3 з JBoss (параграф 5.12)
1.4. Завантаження прикладів з
На сайті, де розміщено цей документ, розглянуті приклади можна завантажити у вигляді zip-файлу, який після розпакування створює таку папку:
![]() |
- у [1]: структура прикладів
- у [2]: папка <annexes> містить елементи, представлені в розділі ANNEXES, параграф 5. Зокрема, папка <jdbc> містить драйвери JDBC з SGBD, які використовуються для прикладів у посібнику.
- у [3]: папка <lib> об’єднує в 5 папок різні архіви .jar, що використовуються в посібнику
- у [4]: папка <lib/divers> містить такі архіви: - драйвери JDBC з SGBD - інструменту модульного тестування [testNG] - інструменту ведення журналів [log4j]
![]() |
- у [5]: архіви реалізації JPA/Hibernate та сторонніх інструментів, необхідних для роботи з Hibernate
- в [6]: архіви реалізації JPA/Toplink
- в [7]: архіви Spring 2.x та сторонніх інструментів, необхідних для Spring
- у [8]: архіви контейнера EJB3 з JBoss
![]() |
- у [9]: папка <hibernate> містить приклади, оброблені за допомогою шару персистентності JPA/Hibernate
- у [10]: папка <hibernate/direct> містить приклади, де шар JPA використовується безпосередньо з програмою типу [Main].
- у [11] та [12]: приклади, де шар JPA використовується через шари [metier] та [dao] у багатошаровій архітектурі, що є типовим випадком використання. Сервіси (пул з’єднань, менеджер транзакцій) , що використовуються рівнями [metier] та [dao], надаються або Spring [11], або JBoss EJB3 [12].
![]() |
- у [13]: папка <toplink> містить приклади з папки <hibernate> [9], але цього разу з рівнем персистентності JPA/Toplink замість JPA/Hibernate. УУ [13] немає папки <jbossejb3>, оскільки не вдалося реалізувати приклад, у якому рівень збереження даних забезпечується Toplink, а сервіси — контейнером EJB3 з JBoss.
- У [14]: папка <web> містить три приклади веб-додатків із шаром персистентності JPA:
- [15]: приклад із використанням Spring / JPA / Hibernate
- [16]: той самий приклад із Spring / JPA / Toplink
- [17]: той самий приклад із JBoss, EJB3 та JPA / Hibernate. Цей приклад не працює, ймовірно, через невиявлену проблему з конфігурацією. Проте його було залишено, щоб читач міг до нього долучитися та, можливо, знайти рішення цієї проблеми.
У цьому посібнику часто згадується ця папкова структура, зокрема під час тестування розглянутих прикладів. Читачеві пропонується завантажити ці приклади та встановити їх. Надалі ми будемо називати <приклади> описану вище папкову структуру з прикладами.
1.5. Налаштування проектів Eclipse для прикладів
У прикладах використовуються «користувацькі» бібліотеки. Це архівні файли .jar, об’єднані під однією назвою. Коли таку бібліотеку додають до classpath проекту Java, усі архівні файли, що містяться в ній, включаються до цього classpath. Давайте розглянемо, як це зробити в Eclipse:
![]() |
- у [1]: [Window / Preferences / Java / Buld Path / User Libraries]
- у [2]: створюємо нову бібліотеку
- в [3]: надаємо їй ім’я та підтверджуємо
![]() |
- в [4]: вибираємо JAR-файли, які увійдуть до бібліотеки [jpa-divers]
- у [5]: вибираємо всі JAR-файли з папки <exemples>/lib/divers
![]() |
- в [6]: визначено бібліотеку користувача [jpa-divers]
- в [7]: повторюємо ту саму процедуру, щоб створити ще 4 бібліотеки:
Бібліотека | Папка з файлами JAR бібліотеки |
<приклади>/lib/hibernate | |
<приклади>/lib/toplink | |
<приклади>/lib/spring | |
<приклади>/lib/jbossejb3 |













