4.1 역사 속으로의 소풍

Java 개체를 데이터베이스에 저장하는 작업은 Java 언어가 생성된 직후에 관련이 있었습니다. 당시 Java 언어에는 UNIX 시간 표준(1970년 이후의 밀리초 수)에 따라 시간을 저장하는 날짜라는 데이터 유형이 하나뿐이었습니다.

글쎄, 그 당시 데이터베이스에는 이미 날짜에 대한 다른 데이터 유형이 있었고 최소한 날짜, 시간 및 날짜 + 시간에 대한 별도의 유형이 있었습니다.

  • 날짜
  • 시간
  • 타임스탬프

따라서 Java 언어의 작성자는 클래스가 포함된 java.sql이라는 특수 패키지를 추가했습니다.

  • java.sql.날짜
  • java.sql.시간
  • java.sql.타임스탬프

이러한 클래스를 매핑하는 것은 정말 즐거운 일입니다.


@Entity
public class TemporalValues {
 
	@Basic
    private java.sql.Date sqlDate;
 
	@Basic
    private java.sql.Time sqlTime;
 
    @Basic
    private java.sql.Timestamp sqlTimestamp;
}

그러나 프로그래머들은 클래스로 작업하곤 했기 때문에 Hibernate는 Date 유형의 매핑을 제어하기 위해 java.util.Date특별한 주석을 추가했습니다 .@Temporal

예:

// If the annotation is missing, then the database will have a TIMESTAMP type
Date dateAsTimestamp;

@Temporal(TemporalType.DATE) // will be mapped to DATE type
Date dateAsDate;

@Temporal(TemporalType.TIME) // will be mapped to TIME type
Date dateAsTime;

유형 java.util.Calendarjava.util.Date기본 유형은 TIMESTAMP 유형을 사용하여 데이터베이스에서 이를 나타냅니다.

4.2 새로운 시간

현재 매핑을 사용하면 모든 것이 훨씬 간단하고 좋습니다. 모든 데이터베이스는 시간과 관련된 4가지 유형의 데이터를 지원합니다.

  • 날짜 - 날짜: 년, 월, 일.
  • TIME - 시간: 시, 분, 초.
  • TIMESTAMP - 날짜, 시간 및 나노초.
  • TIMESTAMP WITH TIME ZONE - TIMESTAMP 및 시간대(구역 이름 또는 오프셋).

유형을 나타내기 위해 날짜java.time.LocalDateJava에서는 JDK 8 DateTime API의 클래스를 사용해야 합니다 .

유형시간데이터베이스에서 Java의 두 가지 유형인 java.time.LocalTime및 로 나타낼 수 있습니다 java.time.OffsetTime. 복잡한 것은 없습니다.

그리고 유형으로 표시되는 정확한 날짜와 시간타임스탬프기본적으로 Java에서는 4가지 유형으로 나타낼 수 있습니다.

  • java.time.Instant
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

그리고 마지막으로시간대가 있는 타임스탬프두 가지 유형으로 나타낼 수 있습니다.

  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

당신은 이미 DateTime API 에 익숙하기 때문에 , 이 문제를 기억하는 것은 당신에게 어렵지 않을 것입니다 :)

그것들을 매핑하는 것은 순수한 즐거움입니다.

@Basic
private java.time.LocalDate localDate;

@Basic
private java.time.LocalTime localTime;

@Basic
private java.time.OffsetTime offsetTime;

@Basic
private java.time.Instant instant;

@Basic
private java.time.LocalDateTime localDateTime;

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

주석은 @Basic필드가 자동 으로 처리되어야 함을 의미합니다 . Hibernate는 이 필드가 매핑되어야 하는 열과 유형을 결정합니다.

4.3 시간대 작업

시간대가 날짜의 일부인 경우 데이터베이스에 저장하는 것은 일반 날짜와 마찬가지로 간단합니다.

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

그러나 날짜와 별도로 시간대를 저장하려면 다음을 수행하십시오.

@Basic
private java.time.TimeZone timeZone;

@Basic
private java.time.ZoneOffset zonedOffset;

그런 다음 Hibernate는 기본적으로 VARCHAR 유형에 저장합니다. TimeZone에는 일반적으로 "UTC + 3" 또는 "Cairo"와 같은 문자열 이름이 있기 때문에 이는 논리적입니다.

4.4 나만의 시간대 설정

데이터베이스에 날짜를 저장하는 작업을 할 때 현재 시간대를 설정할 수 있는 위치가 이미 4개 있다는 사실을 알게 될 것입니다.

  • 서버 운영체제;
  • DBMS;
  • 자바 애플리케이션
  • 최대 절전 모드.

DBMS가 시간대(TimeZone)를 지정하지 않으면 운영 체제 설정에서 가져옵니다. 백업 DBMS는 자체 시간대가 있는 다른 데이터 센터에 있는 경우가 많기 때문에 이는 불편할 수 있습니다.

따라서 거의 모든 DBMS 관리자는 한 서버에서 다른 서버로 데이터를 쉽게 전송할 수 있도록 단일 영역을 설정합니다.

상황은 Java 애플리케이션과 유사합니다. 또한 다른 데이터 센터의 다른 서버에서 실행될 수 있으므로 일반적으로 명시적인 시간대가 있습니다.


java -Duser.timezone=UTC ...

또는 프로그램이 실행되는 동안:

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

그리고 물론 Hibernate는 시간대를 명시적으로 설정할 수 있게 해준다.

첫째, SessionFactory를 구성할 때 지정할 수 있습니다.

settings.put(
    AvailableSettings.JDBC_TIME_ZONE,
    TimeZone.getTimeZone("UTC")
);

둘째, 시간대를 지정할 수 있습니다.특정 세션에 대해:

Session session = sessionFactory()
    .withOptions()
    .jdbcTimeZone(TimeZone.getTimeZone("UTC"))
    .openSession();

4.5 @TimeZoneStorage 주석

프로그래머가 한 국가(및 한 시간대)에서 작업하는 것을 기반으로 데이터베이스 설계를 시작한 다음 몇 년 후에 다른 시간대에서 작업하기 위한 지원을 추가해야 하는 경우가 종종 있습니다.

따라서 시간대를 저장하기 위해 별도의 열을 데이터베이스에 추가했습니다. 이는 Hibernate가 특정 날짜의 TimeZone을 별도의 열에 저장할 수 있도록 하는 특수 주석을 추가한 일반적인 상황입니다.

예:

@TimeZoneStorage(TimeZoneStorageType.COLUMN)
@TimeZoneColumn(name = "birthday_offset_offset")
@Column(name = "birthday_offset")
private OffsetDateTime offsetDateTimeColumn;

@TimeZoneStorage(TimeZoneStorageType.COLUMN)
@TimeZoneColumn(name = "birthday_zoned_offset")
@Column(name = "birthday_zoned")
private ZonedDateTime zonedDateTimeColumn;

이것은 목발입니다. 그러나 이에 대한 변명도 있습니다. DateTime API가 아직 존재하지 않았을 때 나타났습니다. 그리고 클래스에 TimeZone을 저장하는 것은 불가능했습니다 java.util.Date.

나는 당신이 당신의 코드에서 이것을 자주 보지 않기를 정말로 바랍니다.