java.util.Date
vs java.sql.Date
: เมื่อใดที่จะใช้และทำไม
java.util.Date
vs java.sql.Date
: เมื่อใดที่จะใช้และทำไม
คำตอบ:
ขอแสดงความยินดีคุณได้โจมตีสัตว์เลี้ยงตัวโปรดของฉันด้วย JDBC: การจัดการชั้นเรียนวันที่
ฐานข้อมูลโดยทั่วไปจะสนับสนุนอย่างน้อยสามรูปแบบของเขตข้อมูลวันที่และเวลาซึ่งเป็นวันที่เวลาและการประทับเวลา แต่ละเหล่านี้มีระดับที่สอดคล้องกันใน JDBC และแต่ละของพวกเขาขยาย java.util.Date
ซีแมนทิกส์ด่วนของแต่ละสามรายการมีดังต่อไปนี้:
java.sql.Date
สอดคล้องกับ SQL DATE ซึ่งหมายความว่าจะเก็บปีเดือนและวันในขณะที่ละเว้นชั่วโมงนาทีวินาทีและมิลลิวินาที นอกจากนี้sql.Date
จะไม่เชื่อมโยงกับเขตเวลาjava.sql.Time
สอดคล้องกับ SQL เวลาและเป็นควรจะชัดเจนเพียงมีข้อมูลเกี่ยวกับชั่วโมงนาทีวินาทีและมิลลิวินาทีjava.sql.Timestamp
สอดคล้องกับ SQL TIMESTAMP ซึ่งเป็นวันที่แน่นอนกับนาโนวินาที ( โปรดทราบว่าutil.Date
รองรับมิลลิวินาทีเท่านั้น! ) ด้วยความแม่นยำที่ปรับแต่งได้หนึ่งในข้อบกพร่องที่พบบ่อยที่สุดเมื่อใช้ไดรเวอร์ JDBC ที่เกี่ยวข้องกับทั้งสามประเภทคือประเภทที่ได้รับการจัดการอย่างไม่ถูกต้อง ซึ่งหมายความว่าsql.Date
เป็นเขตเวลาที่เฉพาะเจาะจงsql.Time
ประกอบด้วยปีปัจจุบันเดือนและวันและอื่น ๆ
ขึ้นอยู่กับชนิดของฟิลด์ SQL จริงๆ PreparedStatement
มี setters สำหรับทั้งสามค่า#setDate()
เป็นหนึ่งสำหรับsql.Date
, #setTime()
สำหรับsql.Time
และสำหรับ#setTimestamp()
sql.Timestamp
โปรดทราบว่าถ้าคุณใช้ps.setObject(fieldIndex, utilDateObject);
คุณสามารถให้util.Date
ไดร์เวอร์ JDBC ปกติซึ่งปกติจะกินได้อย่างมีความสุขราวกับว่ามันเป็นประเภทที่ถูกต้อง แต่เมื่อคุณขอข้อมูลในภายหลังคุณอาจสังเกตเห็นว่าคุณขาดอะไรจริง ๆ
สิ่งที่ฉันกำลังพูดที่ช่วยประหยัดมิลลิวินาที / nanoseconds เป็น longs ธรรมดาและแปลงให้เป็นวัตถุใด ๆ ที่คุณใช้ ( ปลั๊ก joda เวลาบังคับ ) วิธีแฮ็คหนึ่งที่สามารถทำได้คือการจัดเก็บองค์ประกอบวันที่เป็นองค์ประกอบหนึ่งที่ยาวและเวลาเป็นอีกหนึ่งตัวอย่างเช่นตอนนี้จะเป็น 20100221 และ 154536123 ตัวเลขมายากลเหล่านี้สามารถใช้ในแบบสอบถาม SQL และจะพกพาจากฐานข้อมูลไปยังอีกและ จะช่วยให้คุณหลีกเลี่ยงส่วนนี้ของ JDBC / Java Date API: s ทั้งหมด
LATE EDIT:เริ่มต้นด้วย Java 8 คุณไม่ควรใช้java.util.Date
หรือ java.sql.Date
ถ้าคุณสามารถหลีกเลี่ยงได้และควรใช้java.time
แพ็คเกจ (ตาม Joda) แทนการใช้อย่างอื่นแทน หากคุณไม่ได้ใช้ Java 8 ต่อไปนี้เป็นคำตอบดั้งเดิม:
java.sql.Date
- เมื่อคุณเรียกเมธอด / ตัวสร้างของไลบรารีที่ใช้มัน (เช่น JDBC) ไม่อย่างอื่น คุณไม่ต้องการแนะนำการพึ่งพาไลบรารีฐานข้อมูลสำหรับแอ็พพลิเคชัน / โมดูลที่ไม่ได้จัดการกับ JDBC อย่างชัดเจน
java.util.Date
- เมื่อใช้ไลบรารีที่ใช้งาน มิฉะนั้นน้อยที่สุดด้วยเหตุผลหลายประการ:
มันไม่แน่นอนซึ่งหมายความว่าคุณต้องทำสำเนาการป้องกันไว้ทุกครั้งที่คุณส่งหรือส่งคืนจากวิธีการ
มันไม่สามารถจัดการกับวันที่ได้เป็นอย่างดีซึ่งคนหลังเหมือนคุณอย่างแท้จริงคิดว่าการจัดการชั้นเรียนวันที่ควร
ตอนนี้เนื่องจาก juD ทำงานได้ไม่ดีนักCalendar
ชั้นเรียนที่น่ากลัวจึงถูกนำมาใช้ พวกเขายังไม่แน่นอนและน่ากลัวที่จะทำงานด้วยและควรหลีกเลี่ยงหากคุณไม่มีทางเลือก
มีทางเลือกที่ดีกว่าเช่น Joda Time API ( ซึ่งอาจทำให้เป็น Java 7 และกลายเป็น API จัดการวันที่ใหม่อย่างเป็นทางการ - การค้นหาอย่างรวดเร็วบอกว่าจะไม่)
หากคุณรู้สึกว่าเกินความสามารถในการแนะนำการพึ่งพาใหม่เช่น Joda long
ไม่ใช่สิ่งที่ไม่ดีเลยที่จะใช้สำหรับเขตข้อมูลประทับเวลาในวัตถุแม้ว่าตัวฉันเองมักจะห่อมันไว้ใน juD เมื่อผ่านมันไปเพื่อความปลอดภัยประเภทและเป็นเอกสาร
java.sql.Date
กับPreparedStatement
อื่น ๆ ! แต่เมื่อคุณผ่านมันไปให้ใช้สิ่งLocalDate
ที่คุณแปลงโดยใช้java.sql.Date.valueOf
และjava.sql.Date.valueOf
เมื่อทำการตั้งค่าและแปลงมันกลับมาให้เร็วที่สุดเท่าที่จะทำได้โดยใช้java.sql.Date.toLocalDate
อีกครั้งเพราะคุณต้องการที่จะใช้ java.sql ให้น้อยที่สุดเท่าที่จะทำได้
เวลาเท่านั้นที่จะใช้งานอยู่ในjava.sql.Date
มิฉะนั้นการใช้งานPreparedStatement.setDate
java.util.Date
มันบอกว่าResultSet.getDate
ผลตอบแทนแต่ก็สามารถได้รับมอบหมายโดยตรงกับjava.sql.Date
java.util.Date
java.sql.Date
สามารถถูกกำหนดให้กับ a java.util.Date
เมื่ออดีตขยายส่วนหลัง? ประเด็นที่คุณพยายามทำคืออะไร?
ฉันมีปัญหาเดียวกันวิธีที่ง่ายที่สุดที่ฉันพบเพื่อแทรกวันที่ปัจจุบันลงในคำสั่งที่เตรียมไว้คือ:
preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
ไม่ใช้
java.time.Instant
แทนที่ java.util.Date
java.time.LocalDate
แทนที่ java.sql.Date
java.util.Date vs java.sql.Date: จะใช้เมื่อใดและเพราะเหตุใด
ทั้งสองคลาสนี้แย่มากข้อบกพร่องในการออกแบบและการนำไปใช้งาน หลีกเลี่ยงเช่นภัยพิบัติ Coronavirus
ใช้คลาสjava.timeแทนซึ่งกำหนดไว้ใน JSR 310 คลาสเหล่านี้เป็นกรอบงานชั้นนำของอุตสาหกรรมสำหรับการทำงานกับการจัดการวันที่ แทนที่เหล่านี้อย่างสิ้นเชิงเลือดเรียนมรดกอันยิ่งใหญ่เช่นDate
, Calendar
, SimpleDateFormat
และเช่น
java.util.Date
ครั้งแรกjava.util.Date
หมายถึงการแสดงช่วงเวลาใน UTC หมายถึงการชดเชยจาก UTC เป็นศูนย์ชั่วโมง - นาที - วินาที
java.time.Instant
java.time.Instant
ตอนนี้ถูกแทนที่ด้วย
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC.
java.time.OffsetDateTime
Instant
เป็นพื้นฐานระดับอาคารบล็อกของjava.time เพื่อความยืดหยุ่นมากขึ้นให้ใช้การOffsetDateTime
ตั้งค่าเพื่อZoneOffset.UTC
จุดประสงค์เดียวกัน: แสดงช่วงเวลาใน UTC
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
คุณสามารถส่งวัตถุนี้ไปยังฐานข้อมูลโดยใช้PreparedStatement::setObject
กับJDBC 4.2 หรือใหม่กว่า
myPreparedStatement.setObject( … , odt ) ;
กู้
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
java.sql.Date
java.sql.Date
ชั้นยังเป็นที่น่ากลัวและล้าสมัย
คลาสนี้มีไว้เพื่อแสดงถึงวันที่เท่านั้นโดยไม่มีช่วงเวลาของวันและไม่มีเขตเวลา น่าเสียดายที่การแฮ็กของการออกแบบแย่มากคลาสนี้สืบทอดมาจากjava.util.Date
ช่วงเวลาหนึ่ง (วันที่มีเวลาใน UTC) ดังนั้นคลาสนี้ทำท่าว่าจะเป็นวันที่เท่านั้นในขณะที่มีการชดเชยเวลาของวันและโดยปริยายของ UTC ทำให้เกิดความสับสนอย่างมาก อย่าใช้คลาสนี้
java.time.LocalDate
ให้ใช้java.time.LocalDate
เพื่อติดตามเฉพาะวันที่ (ปี, เดือน, วันของเดือน) โดยไม่มีการแจ้งเตือนเวลาหรือเขตเวลาใด ๆ หรือออฟเซ็ต
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate ld = LocalDate.now( z ) ; // Capture the current date as seen in the wall-clock time used by the people of a particular region (a time zone).
ส่งไปยังฐานข้อมูล
myPreparedStatement.setObject( … , ld ) ;
กู้
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
java.timeกรอบถูกสร้างขึ้นใน Java 8 และต่อมา ชั้นเรียนเหล่านี้แย่งลำบากเก่ามรดกเรียนวันที่เวลาเช่นjava.util.Date
, และCalendar
SimpleDateFormat
ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ออราเคิลกวดวิชา และค้นหา Stack Overflow สำหรับตัวอย่างและคำอธิบายมากมาย สเปกJSR 310
Joda เวลาโครงการขณะนี้อยู่ในโหมดการบำรุงรักษาให้คำแนะนำแก่การโยกย้ายไปยังjava.timeชั้นเรียน
คุณสามารถแลกเปลี่ยนวัตถุjava.timeโดยตรงกับฐานข้อมูลของคุณ ใช้ไดรเวอร์ JDBC ที่สอดคล้องกับJDBC 4.2หรือใหม่กว่า ไม่จำเป็นต้องใช้สตริงไม่จำเป็นต้องใช้java.sql.*
คลาส
จะรับคลาส java.time ได้ที่ไหน?
คลาส java.util.Date ใน Java แสดงช่วงเวลาเฉพาะ (e, .g., 2013 25 พฤศจิกายน 16:30:45 น. เป็นมิลลิวินาที) แต่ประเภทข้อมูล DATE ใน DB แสดงวันที่เท่านั้น (เช่น 2013 พ.ย. 25) เพื่อป้องกันไม่ให้คุณให้วัตถุ java.util.Date กับฐานข้อมูลโดยไม่ได้ตั้งใจ Java ไม่อนุญาตให้คุณตั้งค่าพารามิเตอร์ SQL เป็น java.util.Date โดยตรง:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, d); //will not work
แต่มันยังช่วยให้คุณสามารถทำเช่นนั้นได้โดยการบังคับ / เจตนา (จากนั้นโปรแกรมควบคุม DB จะไม่สนใจชั่วโมงและนาที) สิ่งนี้ทำกับคลาส java.sql.Date:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, new java.sql.Date(d.getTime())); //will work
วัตถุ java.sql.Date สามารถเก็บช่วงเวลา (เพื่อให้ง่ายต่อการสร้างจาก java.util.Date) แต่จะส่งข้อยกเว้นถ้าคุณพยายามขอชั่วโมง (เพื่อบังคับใช้แนวคิดในการเป็น วันที่เท่านั้น) คาดว่าไดรเวอร์ DB จะรู้จักคลาสนี้และเพียงแค่ใช้ 0 สำหรับชั่วโมง ลองสิ่งนี้:
public static void main(String[] args) {
java.util.Date d1 = new java.util.Date(12345);//ms since 1970 Jan 1 midnight
java.sql.Date d2 = new java.sql.Date(12345);
System.out.println(d1.getHours());
System.out.println(d2.getHours());
}
java.util.Date
แสดงถึงเวลาที่กำหนดโดยทันทีด้วยความแม่นยำมิลลิวินาที มันแสดงให้เห็นถึงข้อมูลวันที่และเวลาที่ไม่มีเขตเวลา คลาส java.util.Date ใช้อินเตอร์เฟสแบบ Serializable, Cloneable และ Comparable มันเป็นกรรมพันธุ์ด้วยjava.sql.Date
, java.sql.Time
และjava.sql.Timestamp
อินเตอร์เฟซ
java.sql.Date
ขยายคลาส java.util.Date ซึ่งแสดงวันที่โดยไม่มีข้อมูลเวลาและควรใช้เฉพาะเมื่อจัดการกับฐานข้อมูล เพื่อให้สอดคล้องกับคำจำกัดความของ SQL DATE ค่ามิลลิวินาทีที่ห่อด้วยjava.sql.Date
อินสแตนซ์จะต้องเป็น 'ปกติ' โดยการตั้งค่าชั่วโมงนาทีวินาทีและมิลลิวินาทีเป็นศูนย์ในเขตเวลาเฉพาะที่เกี่ยวข้องกับอินสแตนซ์
มันสืบทอดวิธีการสาธารณะทั้งหมดjava.util.Date
เช่นgetHours()
, getMinutes()
, getSeconds()
, setHours()
, ,setMinutes()
setSeconds()
ตามที่java.sql.Date
ไม่ได้เก็บข้อมูลเวลามันจะแทนที่การดำเนินการเวลาjava.util.Date
ทั้งหมดและวิธีการทั้งหมดเหล่านี้จะดำเนินการjava.lang.IllegalArgumentException
หากเรียกใช้ตามที่เห็นได้ชัดจากรายละเอียดการใช้งาน