Аннотации Java для работы с базой данных
Рассмотрим аннотации, которые используются в стандарте JPA и в различных фреймворках вроде Hibernate.
@Entity | javax.persistence.Entity |
@Table | javax.persistence.Table |
@Column | javax.persistence.Table |
@Id | javax.persistence.Id |
@GeneratedValue | javax.persistence.GeneratedValue |
@Version | javax.persistence.Version |
@OrderBy | javax.persistence.OrderBy |
@Transient | javax.persistence.Transient |
@Lob | javax.persistence.Lob |
@PersistenceContext | javax.persistence.PersistenceContext |
@Temporal | javax.persistence.TemporalType |
@Embedded | javax.persistence.Embedded |
Аннотации для связи ассоциаций | |
@OneToOne | javax.persistence.OneToOne |
@ManyToOne | javax.persistence.ManyToOne |
@OneToMany | javax.persistence.OneToMany |
@ManyToMany | javax.persistence.ManyToMany |
@PrimaryKeyJoinColumn | javax.persistence.PrimaryKeyJoinColumn |
@JoinColumn | javax.persistence.PrimaryKeyJoinColumn |
@JoinTable | javax.persistence.JoinTable |
@MapsId | javax.persistence.MapsId |
Аннотации наследования | |
@Inheritance | javax.persistence.Inheritance |
@DiscriminatorColumn | javax.persistence.DiscriminatorColumn |
@DiscriminatorValue | javax.persistence.DiscriminatorValue |
Аннотации запросов | |
@NamedQueries | javax.persistence.NamedQueries |
@NamedQuery | javax.persistence.NamedQuery |
@SqlResultSetMapping | javax.persistence.SqlResultSetMapping |
@EntityResult | javax.persistence.EntityResult |
Аннотации Hibernate | |
@Audited | org.hibernate.envers.Audited |
@NotAudited | org.hibernate.envers.NotAudited |
@Type | org.hibernate.annotations.Type |
@Entity — Указывает, что данный бин (класс) является сущностью.
Маппинг примитивных типов данных
Во время предыдущих трех уровней мы немного познакомились с 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
Задания типа вручную – аннотация @Type
Иногда ты можешь захотеть вмешаться в политику Hibernate и явно указать ему в каком типе нужно хранить данные в базе. Например, у тебя в Entity-классе поле имеет тип Integer, но в базе для него есть колонка с типом VARCHAR.
Для этого есть специальная аннотация – @Type . Выглядит она очень просто:
Давай, например, попросим Hibernate, чтобы поле createdDate нашего класса User хранилось в базе в виде строки:
@Entity @Table(name="user") class User
Если 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 и его часто хранят так:
Поэтому очень хорошо, когда 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 |