Hozirgi vaqtdagi holatlar
JDBC o'ylab topilganidan beri 20 yil o'tdi va shu vaqt ichida ko'p narsa o'zgardi.
Birinchidan, dunyo global bo'lib qoldi va endi bitta server butun dunyo bo'ylab foydalanuvchilarga xizmat ko'rsatishi mumkin. Internet tezligi hal qiladi. Shuning uchun SQL ga yana bir ma'lumot turi qo'shildi vaqt bilan ishlash uchun. Endi turlar quyidagicha ko'rinadi:
- DATE – sana saqlaydi: yil, oy, kun.
- TIME – vaqt saqlaydi: soat, daqiqa, soniya.
- TIMESTAMP – aniq vaqt lahzasini saqlaydi: sana, vaqt va millisekundlar.
- TIMESTAMP WITH TIME ZONE – TIMESTAMP va vaqt zonasi (zona nomi yoki siljish).
Ikkinchidan, Java da global vaqt bilan ishlash uchun DateTime API paydo bo'ldi. Unda quyidagi sinflar paydo bo'ldi:
- Sana va vaqt:
- LocalDate
- LocalTime
- Aniq lahza:
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
- Vaqt zonasi bilan vaqt:
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Uchinchidan, juda ko'p SQL mijozlari vaqtni serverdan o'zining mahalliy zonasida olishni xohlashadi. Vaqtni on the fly o'zgartirish mumkin albatta, lekin bu noqulay va xatolar bo'lishi mumkin.
Masalan, men bugungi barcha vazifalarni bazadan olishni xohlayman. SQL serverida CURDATE() funksiyasi bor. Faqat server AQShda joylashgan, men esa Yaponiya. Va shuni xohlaymanki, u menga “mening bugunimdagi” barcha yozuvlarni bersin, nafaqat “uning bugunida”.
Umumiy qilib aytganda, SQL server ham turli vaqt zonalaridagi mijozlar bilan aqlli ishlay olishi kerak.
Zamonaviy muammolar zamonaviy yechimlar talab qiladi
Aslida, Java DateTime API va SQL turlarining yangi turlarini mos ravishda bog'lash qulay. Tipini tasvirlash uchun DATE Java da JDK 8 DateTime API ichida java.time.LocalDate sinfini ishlatish kerak.
Ma'lumotlar bazasidagi TIME turini Java ikki turi bilan ifodalash mumkin: java.time.LocalTime va java.time.OffsetTime. Hech qanday qiyinchilik yo'q.
Ma'lumotlar bazasida TIMESTAMP turida ifodalangan aniq vaqt lahzasini Java da 4 turda ifodalash mumkin:
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Va nihoyat, TIMESTAMP WITH TIME ZONE ikki turda ifodalanishi mumkin:
- java.time.OffsetDateTime
- java.time.ZonedDateTime
DateTime API bilan tanish bo'lganligingiz sababli, bu narsalarni eslab qolish siz uchun qiyin bo'lmaydi :)
Buni jadval ko'rinishida yozaman, shunda osonroq bo'ladi:
| SQL TYPE | Java Type |
|---|---|
| DATE | java.time.LocalDate |
| TIME | java.time.LocalTime java.time.OffsetTime |
| TIMESTAMP | java.time.Instant java.time.LocalDateTime java.time.OffsetDateTime java.time.ZonedDateTime |
| TIMESTAMP WITH TIME ZONE | java.time.OffsetDateTime java.time.ZonedDateTime |
Sanani olish
Siz uchun yaxshi yangiliklarim bor. Ko'p vaqt ichida birinchi marta. Biz java.sql Date tipini qaytaradigan getDate() metodining cheklovini aylanib o'tishimiz mumkin.
Gap shundaki, ResultSet obyektida yana bir qiziqarli metod bor — getObject(). Ushbu metod ikki parametrni qabul qiladi: ustun va tip, va ustun qiymatini berilgan tipga aylantirilgan holda qaytaradi. Metodning umumiy ko'rinishi quyidagicha:
ImyaKlass nomi = getObject(kolonka, ImyaKlass);
Va agar siz DATE turini java.time.LocalDate turiga aylantirmoqchi bo'lsangiz, quyidagi kabi yozishingiz kerak:
LocalDate localDate = results.getObject(4, LocalDate.class);
Umuman olganda, har qanday TIMESTAMPni ko'plab turlarga aylantirish mumkin:
java.time.Instant instant = results.getObject(9, java.time.Instant.class);
java.time.LocalDateTime local = results.getObject(9, java.time. LocalDateTime.class);
java.time.OffsetDateTime offset = results.getObject(9, java.time. OffsetDateTime.class);
java.time.ZonedDateTime zoned = results.getObject(9, java.time. ZonedDateTime.class);
Muqaddas! Agar sizda eski MySQL JDBC Driver bo'lsa, bu kod ishlamaydi. pom.xml faylingizda yoki loyihaning Libraries sozlamalariga qo'shilgan “mysql-connector-java” versiyasiga e'tibor bering.
Aytgancha, primitiv turlarda nullni saqlash imkonsizligini ham shu tarzda chetlab o'tish mumkin. Agar jadvalning ustuni INT tipiga ega bo'lsa, u holda undan null olishning bir nechta usuli mavjud. Quyidagi misolga e'tibor bering:
Integer id1 = results.getObject(8, Integer.class); //bu ishlaydi
Integer id2 = results.getObject(8, int.class); //bu ham ishlaydi
int id3 = results.getObject(8, Integer.class); //metod nullni qaytaradi, JVM NPE chiqadi
int id4 = results.getObject(8, int.class); //metod nullni qaytaradi, JVM NPE chiqadi
MySQL da vaqt zonasini sozlash
MySQL bilan ham ko'p qiziqarli ishlar bo'ldi. Sen bilganingdek, MySQL bilan bog'lanishni yaratganda unga turli parametrlar qo'shishingiz mumkin:mysql://localhost:3306/db_scheme?nomi=qiymat&nomi=qiymat
Shunday qilib, vaqt zonalari bilan ishlash uchun MySQL da uchta parametr qo'shildi. Ushbu parametrlarni server bilan bog'lanishni amalga oshirganda o'tkazishingiz mumkin.
Quyida ularning jadvalini keltiraman:
| Parametr | Qiymatlar | Standart qiymati |
|---|---|---|
| connectionTimeZone | LOCAL | SERVER | user-zone | SERVER |
| forceConnectionTimeZoneToSession | true | false | true |
| preserveInstants | true | false | false |
connectionTimeZone parametri yordamida biz barcha so'rovlar bajariladigan vaqt zonasini tanlaymiz. Mijozning nuqtai nazaridan, server ko'rsatilgan vaqt zonasida ishlaydi.
forceConnectionTimeZoneToSession parametri sessiya time_zonesini e'tiborsiz qoldirib, uni connectionTimeZone ga almashtirishga majbur qiladi.
Va nihoyat, preserveInstants parametri aniq lahzalarni JVM timeZone va connectionTimeZone o'rtasida o'zgartirishni boshqaradi.
Eng tez-tez ishlatiladigan konfiguratsiyalar quyidagilardir:
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false — MySQL JDBC eski drayveri versiyasi 5.1 bilan useLegacyDatetimeCode=true parametri bilan mos keladi.
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true — vaqt qiymatlarini eng tabiiy tarzda qayta ishlashni ta'minlaydigan yangi rejim.
connectionTimeZone=SERVER & preserveInstants=true — MySQL JDBC eski drayveri versiyasi 5.1 bilan useLegacyDatetimeCode=false parametri bilan mos keladi.
connectionTimeZone=user_defined & preserveInstants=true — serverning vaqt zonasi konnektor tomonidan aniqlanmagan holatni engishga yordam beradi, chunki u CET/CEST kabi umumiy qisqartma sifatida o'rnatilgan.
Ha, sanalar — qiziq mavzu va ular bilan ko'p muammolar mavjud. Aytishadi: bu albatta dahshatli, lekin men qo'rqmayman! :)
GO TO FULL VERSION