1. Обзор
В этом уроке мы рассмотрим типы Hibernate. Эта библиотека предоставляет нам несколько типов, которых нет в ядре Hibernate ORM.
2. Зависимости
Чтобы включить Hibernate Types, мы просто добавим соответствующую зависимость hibernate -types
:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>2.9.7</version>
</dependency>
Это будет работать с версиями Hibernate 5.4, 5.3
и 5.2.
В случае, если версия Hibernate старше, указанное выше значение ArtiftId
будет другим. Для версий 5.1
и 5.0
мы можем использовать hibernate-types-51.
Точно так же для версии 4.3
требуется hibernate-types-43,
а для версий 4.2
и 4.1 требуется hibernate-types-4.
Для примеров в этом руководстве требуется база данных. Используя Docker, мы предоставили контейнер базы данных. Поэтому нам понадобится рабочая копия Docker .
Итак, для запуска и создания нашей базы данных нам нужно всего лишь выполнить:
$ ./create-database.sh
3. Поддерживаемые базы данных
Мы можем использовать наши типы с базами данных Oracle, SQL Server, PostgreSQL и MySQL. Поэтому сопоставление типов в Java с типами столбцов базы данных зависит от используемой нами базы данных. В нашем случае мы будем использовать MySQL и сопоставлять JsonBinaryType
с типом столбца JSON.
Документацию по поддерживаемым сопоставлениям можно найти в репозитории Hibernate Types .
4. Модель данных
Модель данных для этого руководства позволит нам хранить информацию об альбомах и песнях. Альбом имеет обложку и одну или несколько песен. У песни есть исполнитель и длина. Обложка имеет два URL изображения и код UPC. Наконец, у артиста есть имя, страна и музыкальный жанр.
Раньше мы создавали таблицы для представления всех данных в нашей модели. Но теперь, когда у нас есть доступные типы, мы можем очень легко хранить некоторые данные в формате JSON.
В этом уроке мы создадим таблицы только для альбомов и песен:
public class Album extends BaseEntity {
@Type(type = "json")
@Column(columnDefinition = "json")
private CoverArt coverArt;
@OneToMany(fetch = FetchType.EAGER)
private List<Song> songs;
// other class members
}
public class Song extends BaseEntity {
private Long length = 0L;
@Type(type = "json")
@Column(columnDefinition = "json")
private Artist artist;
// other class members
}
Используя JsonStringType
, мы будем представлять обложку и исполнителей в виде столбцов JSON в этих таблицах:
public class Artist implements Serializable {
private String name;
private String country;
private String genre;
// other class members
}
public class CoverArt implements Serializable {
private String frontCoverArtUrl;
private String backCoverArtUrl;
private String upcCode;
// other class members
}
Важно отметить, что классы Artist
и CoverArt
являются объектами POJO, а не сущностями. Кроме того, они являются членами наших классов сущностей базы данных, определенных с помощью аннотации @Type(type = «json»)
.
4.1. Хранение типов JSON
Мы определили наши модели альбомов и песен, чтобы они содержали элементы, которые база данных будет хранить в формате JSON. Это связано с использованием предоставленного типа json
. Чтобы этот тип был доступен для использования, мы должны определить его с помощью определения типа:
@TypeDefs({
@TypeDef(name = "json", typeClass = JsonStringType.class),
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
public class BaseEntity {
// class members
}
@Type для JsonStringType
и JsonBinaryType делает
доступными
типы json
и jsonb
.
``
Последние версии MySQL поддерживают JSON в качестве типа столбца. Следовательно, JDBC обрабатывает любое чтение JSON или любой объект, сохраненный в столбце с любым из этих типов, как String
. Это означает, что для правильного отображения столбца мы должны использовать JsonStringType
в нашем определении типа.
4.2. Спящий режим
В конечном итоге наши типы будут автоматически транслироваться в SQL с помощью JDBC и Hibernate. Итак, теперь мы можем создать несколько объектов песни, объект альбома и сохранить их в базе данных. Впоследствии Hibernate генерирует следующие операторы SQL:
insert into song (name, artist, length, id) values ('A Happy Song', '{"name":"Superstar","country":"England","genre":"Pop"}', 240, 3);
insert into song (name, artist, length, id) values ('A Sad Song', '{"name":"Superstar","country":"England","genre":"Pop"}', 120, 4);
insert into song (name, artist, length, id) values ('A New Song', '{"name":"Newcomer","country":"Jamaica","genre":"Reggae"}', 300, 6)
insert into album (name, cover_art, id) values ('Album 0', '{"frontCoverArtUrl":"http://fakeurl-0","backCoverArtUrl":"http://fakeurl-1","upcCode":"b2b9b193-ee04-4cdc-be8f-3a276769ab5b"}', 7)
Как и ожидалось, все наши Java-объекты типа json переводятся Hibernate и сохраняются в нашей базе данных в виде правильно сформированного JSON.
5. Хранение универсальных типов
Помимо поддержки столбцов на основе JSON, библиотека также добавляет несколько универсальных типов: YearMonth
, Year
и Month
из пакета java.time
.
Теперь мы можем отображать эти типы, которые изначально не поддерживаются Hibernate или JPA . Кроме того, теперь у нас есть возможность хранить их в виде столбца Integer
, String
или Date .
Например, предположим, что мы хотим добавить дату записи песни в нашу модель песни
и сохранить ее как целое число
в нашей базе данных. Мы можем использовать YearMonthIntegerType
в определении нашего класса сущностей Song
:
@TypeDef(
typeClass = YearMonthIntegerType.class,
defaultForType = YearMonth.class
)
public class Song extends BaseEntity {
@Column(
name = "recorded_on",
columnDefinition = "mediumint"
)
private YearMonth recordedOn = YearMonth.now();
// other class members
}
Наше значение свойства RecordOn преобразуется в предоставленный нами
typeClass
. В результате предопределенный преобразователь сохранит значение в нашей базе данных как целое число
.
6. Другие полезные классы
В Hibernate Types есть несколько вспомогательных классов, которые еще больше улучшают работу разработчиков при использовании Hibernate.
CamelCaseToSnakeCaseNamingStrategy сопоставляет
верблюжьи свойства в наших классах Java со змеиными столбцами в нашей базе данных.
ClassImportIntegrator позволяет использовать
простые значения имени класса Java DTO в параметрах конструктора JPA.
Существуют также классы ListResultTransformer
и MapResultTransformer
, предоставляющие более четкие реализации объектов результатов, используемых JPA. Кроме того, они поддерживают использование лямбда-выражений и обеспечивают обратную совместимость со старыми версиями JPA.
7. Заключение
В этом руководстве мы представили библиотеку Java Hibernate Types и новые типы, которые она добавляет в Hibernate и JPA. Мы также рассмотрели некоторые утилиты и универсальные типы, предоставляемые библиотекой.
Реализация примеров и фрагментов кода доступны на GitHub .