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 |
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 |