О Java ORM
Материал из YourcmcWiki
Версия от 22:18, 18 февраля 2016; VitaliyFilippov (обсуждение | вклад)
Содержание
JPA: Hibernate, EclipseLink
Плюсы:
- Наиболее «каноничный» Java ORM
- Есть дополнительные фичи — например, в Hibernate есть Envers, из коробки умеющий логгировать историю изменений сущностей в отдельные таблицы
Минусы:
- Код не лаконичен. Нужно задавать маппинги, классы сущностей, конструировать запросы либо через строковой HQL/JPQL, либо через многословный Criteria…
- Трудно использовать для динамических сущностей (объектов произвольной структуры) — так или иначе нужно конфигурировать маппинг, даже если используется динамическое отображение без классов моделей.
- Возможно, не вполне идеальна логика отображения — конструирование объекта всегда связано с десериализацией, для сохранения ID связанных объектов без самих объектов применяются proxy-классы и ленивая подгрузка (нет возможности одно и то же поле, скажем, person_id, видеть и в виде ID, и в виде объекта)…
- HQL/JPQL — всё-таки недоразумение. Не могу понять смысл реализации собственного строкового языка запросов — SQL если уж во что-то заворачивать, то во что-то объектно-структурированное — хотя бы в объект типа «запрос» с полями tables, where, order by, group by и т. п., но не снова в строковой же литерал! Кроме того, к нему есть различные претензии.
ActiveJPA
Попытка реализации Active Record поверх JPA.
Минусы:
- Велосипедик.
Querydsl
- Для получения красивого Fluent API запросов вместо HQL/JPQL-литералов можно подключить
jOOQ
Плюсы:
- Легковесный Active Record + Fluent API фреймворк.
- Похож на Querydsl, тоже использует кодогенерацию и типобезопасные запросы, однако в дополнение к этому генерирует классы моделей (Active Record) и умеет различные способы получения результатов запросов.
Минусы:
- Трудно/невозможно расширять сгенерированные классы записей (добавлять в них доменную логику).
- Для работы с Oracle нужна платная лицензия — не очень критично, так как для открытых СУБД (MySQL, PostgreSQL и так далее) доступна версия под лицензией Apache 2.0, разрешающей коммерческое использование.
Краткий отзыв — см. например http://teonos.com/blog/java/development/2014/11/10/experiences-with-jOOQ.html
ActiveJDBC
Плюсы:
- Active Record для Java
- Легковесный:
- Необязательны геттеры/сеттеры, поля можно читать по именам model.get("поле")
- Нет ни проксей, ни сессий, ни persistence manager’ов, ни DAO, ни репозиториев, ни «attach/detach», ни собственного языка запросов
Минусы:
- Неотключаемое автоматическое определение таблиц и типов полей во время выполнения. Также есть автоматическая привязка классов к таблицам по правилам английского языка — извращение, но по крайней мере отключаемое.
- Отсутствие поддержки нескольких схем (#144).
- Трудно во время выполнения явно указать соединение БД, с которым должна работать конкретная модель — несколько соединений указывается только на уровне аннотаций во время компиляции, а в рантайме всегда используется текущее «привязанное» к имени соединение.
- Отсутствие доступа к «старым» («чистым») значениям полей при сохранении модели.
- Отсутствие поддержки композитных первичных ключей — всегда нужна автоинкрементная колонка «id», даже в таблицах отношений «многие ко многим»
Ebean ORM
По большей части похож на JPA, те же яйца, только в профиль. Классы размечаются ровно теми же JPA-аннотациями… EbeanServer — тот же аналог сессии или persistence manager’а…
Плюсы:
- Наличие Fluent API запросов, отсутствие велосипедных языков типа JPQL
- Встроенная поддержка сериализации/десериализации JSON
Минусы:
- Серьёзные минусы вроде отсутствуют, разве что логика отображения та же, что в JPA
Идея (велосипедик) — PHP-like ORM
Возможно, описанное примерно соответствует jOOQ. Querydsl тоже чем-то похож, но у него нет класса «Запись».
- Объект «соединение». Умеет делать запросы в синтаксически кратком стиле (возможно, Fluent API) и возвращать записи в виде чего-то типа Map<String,Object>. Кроме того, является аналогом сессии/persistence manager’а для моделей.
- Базовый класс модели хранит запись, полученную из БД, в виде такого же объекта Map, не раскладывая её по своим полям. Благодаря этому создание модели максимально легковесно — это просто вызов конструктора, который делает 1 действие — сохраняет к себе этот Map.
- Все вычислимые значения — например, загружаемые ассоциации — хранятся в ещё одном Map’е. Есть общие геттер и сеттер, работающие по названию поля и возвращающие, кэширующие и вычисляющие дополнительные значения.
- В модели есть ссылка на «грязную»/«чистую» копию и флаг, какой является текущая. Как только кто-то начинает модифицировать модель — объект создаёт свою копию, а сам становится «грязным».
- Логика сохранения в БД также живёт в модели, в виде одного метода типа save(), или, возможно, saveAll(), если в основу класть массовые операции. Это похоже на стиль ActiveRecord, с той только разницей, что в модель всё-таки нужно передавать объект «соединение».
- В модели есть ссылка на resultset, частью которого она является — это позволяет подгружать связи массово.
- Круче всего, если класс модели не абстрактный и позволяет с собой работать вообще без создания дочерних классов.