1. Типи даних, що підтримуються

Під час попередніх трьох рівнів ми трохи познайомилися з Hibernate. Настав час зайти на друге коло. Тепер ми почнемо вивчати те саме, тільки глибше. І почнемо ми з мапінгу полів Entity-класу на колонки таблиць у базі даних.

Як ти вже знаєш, мапінг поля в Entity класі на колонку виконується за допомогою анотації @Column. І тепер питання: а поля яких типів можна замапити такою анотацією?

Всі типи даних у Java можна розбити на три групи:

  • Тип досить простий, і його легко зберегти до бази даних.
  • Тип складний, і для нього потрібно писати спеціальний конвертер.
  • Тип дуже складний, і для зберігання його значень потрібна окрема таблиця.

До простих типів, які Hibernate знає, як зберігати, належать такі:

Типи в мові Java package Приклади класів
Примітивні типи мови Java boolean, int , double тощо.
Обгортки над примітивами java.lang Boolean, Integer , Double тощо.
Рядки java.lang String
"Просунуті" числа java.math BigInteger та BigDecimal
Дата та час java.time LocalDate, LocalTime , LocalDateTime, OffsetTime, OffsetDateTime, Instant
Різні варіації дати та часу java.util Date та Calendar
Старі формати дати та часу java.sql Date, Time , Timestamp
Масив байт або символів byte[] або Byte[], char[] або Character[]
Перерахування (enum) Будь-який enum
Об'єкти, що серіалізуються Будь-яка імплементація java.io.Serializable

Для всіх цих типів є їх аналоги у мові SQL, тому Hibernate добре знає, як їх зберігати та завантажувати з бази.

Приклад:


@Entity
@Table(name="user")
class User
{
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String name;
 
   @Column(name="level")
   public Integer level;
 
   @Column(name="created_date")
   public Date createdDate;
}

2. Встановлення типу вручну — анотація @Type

Іноді ти можеш захотіти втрутитися в політику Hibernate і явно вказати йому, у якому типі потрібно зберігати дані в базі. Наприклад, у тебе в Entity класі поле має тип Integer, але в базі для нього є колонка з типом VARCHAR.

Для цього є спеціальна анотація — @Type. Виглядає вона дуже просто:


@Type(type="ім'я-типу")

Давай, наприклад, попросимо Hibernate, щоб поле createdDate нашого класу User зберігалося у базі у вигляді рядка:


@Entity
@Table(name="user")
class User
{
   @Column(name="id")
    public Integer id;
 
   @Column(name="created_date")
   @Type(type="org.hibernate.type.StringType")
    public Date createdDate;
}

Якщо Hibernate зрозуміє, як конвертувати тип Date у твій новий тип, то просто зробить це. Якщо не зрозуміє, тоді тобі потрібно буде вказати спеціальний конвертер типів. Але про це трохи згодом.

3. Список Hibernate-типів для баз даних

До речі, зверни увагу, що ми вказали тип org.hibernate.type.StringType, а не String. Це тому, що ми вибрали один із типів, який підтримує СУБД, а не мову Java. Усі вони мають власну систему типів. Просто розробники Hibernate придумали зручні назви в стилі Java замість цих VARCHAR-ів.

До речі, цей список не такий уже й маленький. Наведу його частину:

Hibernate type (org.hibernate.type package) JDBC type Java type BasicTypeRegistry key(s)
StringType VARCHAR java.lang.String string, java.lang.String
MaterializedClob CLOB java.lang.String materialized_clob
TextType LONGVARCHAR java.lang.String text
CharacterType CHAR char, java.lang.Character char, java.lang.Character
BooleanType BIT boolean, java.lang.Boolean boolean, java.lang.Boolean
NumericBooleanType INTEGER, 0 is false, 1 is true boolean, java.lang.Boolean numeric_boolean
YesNoType CHAR, 'N'/'n' is false, 'Y'/'y' is true. Uppercase value is written to the database. boolean, java.lang.Boolean yes_no
TrueFalseType CHAR, 'F'/'f' є false, 'T'/'t' є true. Uppercase value is written to the database. boolean, java.lang.Boolean true_false
ByteType TINYINT byte, java.lang.Byte byte, java.lang.Byte
ShortType SMALLINT short, java.lang.Short short, java.lang.Short
IntegerTypes INTEGER int, java.lang.Integer int, java.lang.Integer
LongType BIGINT long, java.lang.Long long, java.lang.Long
FloatType FLOAT float, java.lang.Float float, java.lang.Float
DoubleType DOUBLE double, java.lang.Double double, java.lang.Double
BigIntegerType NUMERIC java.math.BigInteger big_integer, java.math.BigInteger
BigDecimalType NUMERIC java.math.BigDecimal big_decimal, java.math.bigDecimal
TimestampType TIMESTAMP java.sql.Timestamp timestamp, java.sql.Timestamp
TimeType TIME java.sql.Time time, java.sql.Time
DateType DATE java.sql.Date date, java.sql.Date
CalendarType TIMESTAMP java.util.Calendar calendar, java.util.Calendar
CalendarDateType DATE java.util.Calendar calendar_date
CurrencyType java.util.Currency VARCHAR currency, java.util.Currency
LocaleType VARCHAR java.util.Locale locale, java.utility.locale
TimeZoneType VARCHAR, використовуючи TimeZone ID java.util.TimeZone timezone, java.util.TimeZone
UrlType VARCHAR java.net.URL url, java.net.URL
ClassType VARCHAR (class FQN) java.lang.Class class, java.lang.Class

Таблиця, звісно, велика, але дуже корисна. Наприклад, з неї зрозуміло, що тип Boolean можна зберегти до бази як мінімум шістьма різними способами. Тобі стільки не потрібно? А хто сказав, що спосіб збереження обираєш ти?

У SQL немає типу Boolean, і його часто зберігають так:

  • 1 або 0
  • 'F' або 'T'
  • 'Y' або 'N'

Тому дуже добре, коли Hibernate розуміє всі ці проблеми. Або, наприклад, давай візьмемо зберігання масивів даних у базі. Є купа різних варіантів, і Hibernate вміє працювати з ними всіма:

Hibernate type (org.hibernate.type package) JDBC type Java type BasicTypeRegistry
BlobType BLOB java.sql.Blob blog, java.sql.Blob
ClobType CLOB java.sql.Clob clob, java.sql.Clob
BinaryType VARBINARY byte[] binary, byte[]
MaterializedBlobType BLOB byte[] materized_blob
ImageType LONGVARBINARY byte[] image
WrapperBinaryType VARBINARY java.lang.Byte[] wrapper-binary, Byte[], java.lang.Byte[]
CharArrayType VARCHAR char[] characters, char[]
CharacterArrayType VARCHAR java.lang.Character[] wrapper-characters, Character[], java.lang.Character[]
UUIDBinaryType BINARY java.util.UUID uuid-binary, java.util.UUID
UUIDCharType CHAR, can also read VARCHAR java.util.UUID uuid-char
PostgresUUIDType PostgreSQL UUID, через Types#OTHER, які входять до PostgreSQL JDBC driver definition java.util.UUID pg-uuid
А після випуску JDK 8 Hibernate додалося ще кілька типів, пов'язаних з часом. І все для того, щоб спростити тобі життя. Тобі більше не потрібно думати, чи всі ці новомодні типи підтримуються. Творці Hibernate вже додали їхню підтримку для тебе:
Hibernate type (org.hibernate.type package) JDBC type Java type BasicTypeRegistry
DurationType BIGINT java.time.Duration Duration, java.time.Duration
InstantType TIMESTAMP java.time.Instant Instant, java.time.Instant
LocalDateTimeType TIMESTAMP java.time.LocalDateTime LocalDateTime, java.time.LocalDateTime
LocalDateType DATE java.time.LocalDate LocalDate, java.time.LocalDate
LocalTimeType TIME java.time.LocalTime LocalTime, java.time.LocalTime
OffsetDateTimeType TIMESTAMP java.time.OffsetDateTime OffsetDateTime, java.time.OffsetDateTime
OffsetTimeType TIME java.time.OffsetTime OffsetTime, java.time.OffsetTime
OffsetTimeType TIMESTAMP java.time.ZonedDateTime ZonedDateTime, java.time.ZonedDateTime