Поддерживаемые типы данных

Во время предыдущих трех уровней мы немного познакомились с 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;
}

Задания типа вручную – аннотация @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 в ваш новый тип, то просто сделает это. Если не поймет, тогда тебе нужно будет указать специальной конвертор типов. Но об этом немного позднее.

Список 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. The uppercase value is written to the database. boolean, java.lang.Boolean yes_no
TrueFalseType CHAR, 'F'/'f' is false, 'T'/'t' is true. The 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, using the 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 BasicTypeRegistr
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, through Types#OTHER, which complies to the PostgreSQL JDBC driver definition java.util.UUID pg-uuid
А после выпуска JDK 8 в Hibernate добавилось еще несколько типов, связанных со временем. И все с целью упростить тебе жизнь. Тебе больше не нужно думать, поддерживаются ли все эти новомодные типы. Создатели Hibernate уже добавили их поддержку для тебя:
Hibernate type (org.hibernate.type package) JDBC type Java type BasicTypeRegistr
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