4.1 อรรถาธิบายสู่ประวัติศาสตร์
งานบันทึกวัตถุ Java ลงในฐานข้อมูลนั้นเกี่ยวข้องกันแทบจะในทันทีหลังจากสร้างภาษา Java ในเวลานั้น ภาษา Java มีข้อมูลประเภทเดียวคือ Date ซึ่งเก็บเวลาตามมาตรฐาน UNIX-time เป็นจำนวนมิลลิวินาทีตั้งแต่ปี 1970
ในฐานข้อมูลในเวลานั้นมีประเภทข้อมูลที่แตกต่างกันสำหรับวันที่ อย่างน้อยก็มีประเภทแยกต่างหากสำหรับวันที่ เวลา และวันที่ + เวลา:
- วันที่
- เวลา
- ประทับเวลา
ดังนั้นผู้สร้างภาษา Java จึงเพิ่มแพ็คเกจพิเศษ - java.sql ซึ่งมีคลาส:
- java.sql.date
- java.sql.Time
- java.sql.timestamp
การทำแผนที่ชั้นเรียนเหล่านี้เป็นเรื่องที่น่ายินดีอย่างยิ่ง:
@Entity
public class TemporalValues {
@Basic
private java.sql.Date sqlDate;
@Basic
private java.sql.Time sqlTime;
@Basic
private java.sql.Timestamp sqlTimestamp;
}
แต่เนื่องจากโปรแกรมเมอร์เคยทำงานกับคลาสjava.util.Date
Hibernate จึงเพิ่มคำอธิบายประกอบพิเศษ@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.Calendar
และjava.util.Date
ประเภทเริ่มต้นใช้ ประเภท TIMESTAMPเพื่อเป็นตัวแทนในฐานข้อมูล
4.2 เวลาใหม่
ในปัจจุบัน การทำแผนที่ทำให้ทุกอย่างง่ายขึ้นและดีขึ้นมาก ฐานข้อมูลทั้งหมดรองรับข้อมูล 4 ประเภทเพื่อทำงานกับเวลา:
- DATE - วันที่: ปี เดือน และวัน
- TIME - เวลา: ชั่วโมง นาที วินาที
- TIMESTAMP - วันที่ เวลา และนาโนวินาที
- การประทับเวลาด้วยโซนเวลา - การประทับเวลาและโซนเวลา (ชื่อโซนหรือออฟเซ็ต)
เพื่อแสดงถึงประเภท วันที่ใน Java คุณต้องใช้คลาสjava.time.LocalDate
จาก 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
หมายความว่าฟิลด์ควรได้รับการประมวลผลโดยอัตโนมัติ : ไฮเบอร์เนตจะตัดสินใจว่าคอลัมน์ใดและประเภทใดที่ควรแมปฟิลด์นี้
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 ไม่ได้ระบุเขตเวลา (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
บ่อยครั้งที่โปรแกรมเมอร์เริ่มออกแบบฐานข้อมูลตามการทำงานในประเทศหนึ่ง (และโซนเวลาเดียว) และหลังจากนั้นสองสามปี พวกเขาจำเป็นต้องเพิ่มการสนับสนุนสำหรับการทำงานในโซนเวลาที่ต่างกัน
ดังนั้น พวกเขาจึงเพิ่มคอลัมน์แยกต่างหากในฐานข้อมูลเพื่อจัดเก็บโซนเวลา นี่เป็นสถานการณ์ทั่วไปที่ไฮเบอร์เนตได้เพิ่มคำอธิบายประกอบพิเศษที่ให้คุณจัดเก็บโซนเวลาของวันที่ที่ระบุในคอลัมน์แยกต่างหาก
ตัวอย่าง:
@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
เรียน
ฉันหวังว่าคุณจะไม่เห็นสิ่งนี้ในโค้ดของคุณบ่อยๆ
GO TO FULL VERSION