將 OffsetDateTime ZoneOffset 與 Hibernate TimeZoneColumn 進行映射
1. 概述
在 Java 應用程式中保留時間戳記是很常見的,並且通常首選 UTC 時間戳以避免時區複雜性。然而,有時可能需要使用區域偏移來儲存時間戳。
在本文中,我們將了解如何在保留時間戳記的同時儲存OffsetDateTime
和ZoneOffset
。
2. 持久化OffsetDateTime
JPA 開箱即用支援OffsetDateTime
。 OffsetDateTime
表示日期和時間以及相對於 UTC 時間的偏移。
讓我們定義一個保存OffsetDateTime
時間戳記的Entity
:
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@Column(name = "inserted_at_timestamp")
private OffsetDateTime insertedAt;
// standard setters and getters
}
現在,讓我們執行一個測試來驗證 JPA 如何保留此資訊:
@Test
void whenPersistingOffsetDateTime_thenIsPersisted() {
entityManager.getTransaction().begin();
Person person1 = new Person();
person1.setInsertedAt(OffsetDateTime.of(2024,10,31,12,0,0,0, ZoneOffset.ofHours(5)));
entityManager.persist(person1);
Person savedEntity = entityManager.createQuery("from Person", Person.class)
.getSingleResult();
assertNotNull(savedEntity);
entityManager.getTransaction().commit();
}
我們來看看測試的日誌:
Hibernate:
/* insert for
com.baeldung.hibernate.timezonecolumn.model.Person */insert
into
Person (inserted_at_timestamp, id)
values
(?, ?)
#1731106113065 | took 0ms | statement | connection 0| url jdbc:p6spy:h2:mem:test
/* insert for com.baeldung.hibernate.timezonecolumn.model.Person */insert into Person (inserted_at_timestamp,id) values (?,?)
/* insert for com.baeldung.hibernate.timezonecolumn.model.Person */insert into Person (inserted_at_timestamp,id) values ('2024-10-31T12:00+05:00',1);
我們可以在這裡看到,Hibernate 將**OffsetDateTime
與偏移量一起保留在單一列中**。
JPA 使用TIMESTAMP(n) WITH TIME ZONE
(或等效)SQL 類型。然而,並非所有資料庫都支援此功能。
3.使用TimeZoneColumn
持久化OffsetDateTime
要單獨持久化ZoneOffset
或當資料庫不支援OffsetDateTime
時,我們可以使用@TimeZoneColumn
註解將ZoneOffset
單獨保存在資料庫表中。
讓我們透過新增欄位並使用@TimeZoneColumn
註解來更新先前定義的實體:
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@Column(name = "inserted_at_timestamp")
private OffsetDateTime insertedAt;
@Column(name = "updated_at_timestamp")
@TimeZoneStorage(TimeZoneStorageType.COLUMN)
@TimeZoneColumn(name="last_updated_offset")
private OffsetDateTime lastUpdatedAt;
// standard getters and setters
}
JPA 將偏移量儲存在指定的單獨欄位中。
現在,讓我們透過執行測試來驗證這一點:
@Test
void whenPersistingOffsetDateTimeWithTimeZoneColumn_thenIsPersisted() {
entityManager.getTransaction().begin();
Person person1 = new Person();
person1.setLastUpdatedAt(OffsetDateTime.of(2024,10,31,12,0,0,0, ZoneOffset.ofHours(5)));
entityManager.persist(person1);
Person savedEntity = entityManager.createQuery("from Person", Person.class)
.getSingleResult();
assertNotNull(savedEntity);
entityManager.getTransaction().commit();
}
在這裡,我們保留了具有多個時間戳記的實體,以突出使用@TimeZoneColumn
的差異。
讓我們檢查日誌以確認Hibernate將偏移量儲存在單獨的欄位中:
Hibernate:
/* insert for
com.baeldung.hibernate.timezonecolumn.model.Person */insert
into
Person (inserted_at_timestamp, updated_at_timestamp, last_updated_offset, id)
values
(?, ?, ?, ?)
#1731108407719 | took 1ms | statement | connection 0| url jdbc:p6spy:h2:mem:test
/* insert for com.baeldung.hibernate.timezonecolumn.model.Person */insert into Person (inserted_at_timestamp,updated_at_timestamp,last_updated_offset,id) values (?,?,?,?)
/* insert for com.baeldung.hibernate.timezonecolumn.model.Person */insert into Person (inserted_at_timestamp,updated_at_timestamp,last_updated_offset,id) values ('2024-10-30T12:00+05:00','2024-10-31T07:00:00Z',18000,1);
正如我們從 Hibernate 查詢中看到的, ZoneOffset
與時間戳記一起單獨儲存在另一列中。這種拆分使得查詢和維護更加容易。
4. 結論
在本教程中,我們討論了保存OffsetDateTime
的不同方法。
我們學習如何使用@TimeZoneColumn
編寫更易於維護的程式碼。這也確保了與本身可能不支援它的不同資料庫的兼容性。
與往常一樣,完整的源代碼可以在 GitHub 上取得。