Автор оригинала: Vlad Mihalcea.
Теперь, когда Бюллетень для обзора JPA 2.2 был одобрен давайте начнем анализировать некоторые новые дополнения к стандарту, которые уже довольно давно поддерживаются Hibernate. В этой статье мы рассмотрим, как работает JPA 2.2 Дата/время и какие типы необходимо использовать в зависимости от требований вашего бизнес-кейса.
В журнале изменений JPA 2.2 указано, что будут поддерживаться только следующие типы :
В журнале изменений
JPA 2.2
указано, что будут поддерживаться только
следующие типы
:
В то время как LocalDateTime
довольно прост, поскольку он фиксирует только дату и время, OffsetDateTime
более проблематичен, поскольку он фиксирует только смещение, но не правила часового пояса, такие как летнее время (летнее время) или другие правила, определенные ZoneId и обычно поддерживаемые ZonedDateTime
.
Также любопытно, что стандарт не поддерживает java.time.Продолжительность
тип, который может пригодиться во многих случаях использования в бизнесе.
Учитывая, что в нашей системе есть следующие сущности:
Сущность Сотрудник
содержит следующие атрибуты даты и времени Java 8:
день рождения
атрибут являетсяЛокальной датой
, так как нас интересует только часть данныхобновлено
являетсяLocalDateTime
, так как этот атрибут должен хранить информацию как о дате, так и о времени
@Entity(name = "Employee") public class Employee { @Id @GeneratedValue private Long id; @NaturalId private String name; private LocalDate birthday; @Column(name = "updated_on") private LocalDateTime updatedOn; //Getters are setters omitted for brevity }
Для получения более подробной информации об аннотации @Natural
ознакомьтесь с этой статьей .
Сущность Собрание
содержит следующие атрибуты даты и времени Java 8:
начинается с
– этоZoneddatetime
, который, даже если не поддерживается JPA 2.2, вероятно, является более подходящей версиейOffsetDateTime
- атрибут
длительность
может не поддерживаться JPA 2.2, но мы будем использовать его, так как Hibernate поддерживает все эти типы
@Entity(name = "Meeting") public class Meeting { @Id private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "employee_id") private Employee createdBy; @Column(name = "starts_at") private ZonedDateTime startsAt; private Duration duration; //Getters are setters omitted for brevity }
Предполагая, что мы сохраняем следующие сущности:
Employee employee = new Employee(); employee.setName( "Vlad Mihalcea" ); employee.setBirthday( LocalDate.of( 1981, 12, 10 ) ); employee.setUpdatedOn( LocalDateTime.of( 2015, 12, 1, 8, 0, 0 ) ); entityManager.persist( employee ); Meeting meeting = new Meeting(); meeting.setId( 1L ); meeting.setCreatedBy( employee ); meeting.setStartsAt( ZonedDateTime.of( 2017, 6, 25, 11, 30, 0, 0, ZoneId.systemDefault() ) ); meeting.setDuration( Duration.of( 45, ChronoUnit.MINUTES ) ); entityManager.persist( meeting );
Hibernate создаст следующие инструкции SQL:
INSERT INTO Employee ( birthday, name, updated_on, id ) VALUES ( '1981-12-10', 'Vlad Mihalcea', '2015-12-01 08:00:00.0', 1 ) INSERT INTO Meeting ( employee_id, duration, starts_at, id ) VALUES ( 1, 2700000000000, '2017-06-25 11:30:00.0', 1 )
Оба LocalDateTime
и ZonedDateTime
совместно используют org.hibernate.type.descriptor.sql.TimestampTypeDescriptor
, что означает, что они будут сохранены как java.sql.Метка времени
.
Хотя в LocalDateTime
отсутствует информация о часовом поясе, ZonedDateTime
потеряет информацию о часовом поясе при сохранении в соответствующем столбце базы данных.
При загрузке обратно наших объектов:
Employee employee = entityManager .unwrap( Session.class ) .bySimpleNaturalId( Employee.class ) .load( "Vlad Mihalcea" ); assertEquals( LocalDate.of( 1981, 12, 10 ), employee.getBirthday() ); assertEquals( LocalDateTime.of( 2015, 12, 1, 8, 0, 0 ), employee.getUpdatedOn() ); Meeting meeting = entityManager.find( Meeting.class, 1L ); assertSame( employee, meeting.getCreatedBy() ); assertEquals( ZonedDateTime.of( 2017, 6, 25, 11, 30, 0, 0, ZoneId.systemDefault() ), meeting.getStartsAt() ); assertEquals( Duration.of( 45, ChronoUnit.MINUTES ), meeting.getDuration() );
Исходные объекты времени данных Java 8 соответствуют тем, которые сохраняются.
Причина, по которой ZonedDateTime
совпадает с ранее сохраненным, заключается в том, что базовое значение МЕТКИ ВРЕМЕНИ
было перенесено в текущий системный часовой пояс.
Пока все драйверы JDBC не будут поддерживать МЕТКУ ВРЕМЕНИ С ЧАСОВЫМ ПОЯСОМ
на уровне привязки java.sql.Statement
значения параметра , что является требованием для HHH-11773 , сомнительно, что вам действительно нужно использовать ZonedDateTime
или OffsetDateTime
.
В настоящее время гораздо разумнее сохранить все МЕТКА ВРЕМЕНИ
значения в UTC , что означает, что LocalDateTime
гораздо лучше подходит для ваших объектов JPA.