Перейти к основному содержимому

Руководство по библиотеке типов Hibernate

· 5 мин. чтения

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 .