Створення та використання Active Record
Мета: Навчитися використовувати патерн Active Record для взаємодії з базою даних у застосунках. Ознайомитися з основними операціями CRUD (Create, Read, Update, Delete) за допомогою Active Record.
Завдання¶
Необхідно реалізувати систему управління статтями у блозі, де є дві сутності:
- Article (Стаття)
- Comment (Коментар)
Зв'язок
Кожна стаття може мати кілька коментарів (зв’язок "один до багатьох").
- Використайте патерн Active Record.
- Можна використовувати такі мови програмування: Java, C#, C++, Kotlin, PHP, JavaScript.
Хід роботи¶
Демонстрацію патерну Active Record буде проведено на проєкті написаного мовою Java, без використання фреймворків по типу Spring, для чистоти.
Що таке Active Record?¶
Active Record — це патерн проектування, в якому об'єкт, що представляє рядок у звичаній таблиці бази даних, інкапсулює доступ до бази даних, додає логіку домену до цих даних.
Основні характеристики:¶
- Клас = Таблиця: Кожен клас відповідає таблиці в БД.
- Екземпляр = Рядок: Кожен об'єкт класу відповідає конкретному рядку в таблиці.
- Методи = SQL операції: Об'єкт має методи
save(),update(),delete(), які виконують відповідні SQL запити. - Статичні методи: Для пошуку (
findById,findAll) використовуються статичні методи класу.
🏗️ Архітектура та Потік Даних¶
У нашій реалізації ми маємо дві основні сутності: Article (Стаття) та Comment (Коментар).
classDiagram
class ActiveRecord {
<<abstract>>
+save()*
+delete()*
#getConnection() Connection
}
class Article {
-Long id
-String title
-String content
-String author
-Timestamp createdAt
+save()
+delete()
+getComments() List~Comment~
+static findById(Long) Article
+static findAll() List~Article~
}
class Comment {
-Long id
-Long articleId
-String author
-String content
-Timestamp createdAt
+save()
+delete()
+static findById(Long) Comment
+static findAll() List~Comment~
+static findByArticleId(Long) List~Comment~
}
ActiveRecord <|-- Article
ActiveRecord <|-- Comment
Article "1" --> "*" Comment : має
Потік виконання (на прикладі створення статті):¶
- Створюється об'єкт
new Article(...). - Викликається метод
.save(). - Всередині
save()формується SQLINSERT. - Через
DatabaseConnectionотримується з'єднання. - Запит виконується, і згенерований ID присвоюється об'єкту.
🛠️ Нюанси Реалізації¶
Ця реалізація є навчальною та спрощеною. Основні рішення та причини їх прийняття:
-
Прямий JDBC (Java Database Connectivity):
- Чому: Щоб показати "магію", яка відбувається під капотом ORM.
- Як це працює: Ми вручну пишемо SQL запити (
SELECT * FROM...) та мапимоResultSetу поля об'єкта.
-
ActiveRecord як базовий клас:
- Чому: Для винесення спільної логіки (отримання з'єднання) та визначення контракту (
save,delete). - Обмеження: У Java статичні методи не можна перевизначити (override) так само як звичайні, тому методи
find...доводиться дублювати в кожному класі.
- Чому: Для винесення спільної логіки (отримання з'єднання) та визначення контракту (
-
Управління транзакціями:
- Поточний стан: Кожна операція
save()— це окрема транзакція (autocommit). - Недолік: Немає можливості відкотити зміни, якщо, наприклад, збереження статті пройшло, а коментаря — ні.
- Поточний стан: Кожна операція
-
Lazy Loading (Ліниве завантаження) коментарів:
- Метод
article.getComments()робить запит до БД тільки в момент виклику, а не під час завантаження статті. Це економить ресурси, якщо коментарі не потрібні.
- Метод
🚀 Як зробити "по-дорослому"? (Production Ready)¶
Для реальних великих проектів патерн Active Record у чистому вигляді в Java використовується рідко. Зазвичай використовують потужніші інструменти:
1. Spring Data JPA / Hibernate (Data Mapper Pattern)¶
Найпопулярніший підхід у світі Java.
* Чому краще:
* Автоматична генерація SQL (не треба писати руками).
* Керування транзакціями (@Transactional).
* Кешування першого та другого рівня.
* Захист від SQL Injection "з коробки" (хоча ми теж використовуємо PreparedStatement).
* Відмінність: Сутності (Entity) — це просто дані (POJO), а логіка збереження винесена в Репозиторії (Repository).
2. JOOQ (Java Object Oriented Querying)¶
Якщо ви любите SQL і хочете повний контроль, але з типізацією Java.
* Дозволяє писати SQL-подібний код типу: create.selectFrom(ARTICLE).where(ARTICLE.ID.eq(1)).fetch().
3. Panache (Quarkus)¶
Це фреймворк, який якраз реалізує Active Record pattern у світі Java Enterprise (на базі Hibernate).
* Виглядає так: Article.findById(1), article.persist().
* Це ідеальний варіант, якщо вам подобається стиль Active Record, але потрібна потужність Hibernate.
4. MyBatis¶
Дозволяє винести всі SQL запити в XML файли або анотації, відокремлюючи SQL від Java коду.
Висновок¶
Виконання практичної роботи дозволило зрозуміти принцип взаємодії з базою даних згідно патерну Active Record у якому запити відбуваються через сутність.