Zaman içinde mevcut durum

JDBC'nin icat edilip arayüzlerinin standardize edilmesinden bu yana 20 yıl geçti ve bu süre zarfında çok şey değişti.

İlk olarak, dünya küresel hale geldi ve artık tek bir sunucu dünyanın her yerinden kullanıcılara hizmet verebilir. İnternet hızı arttı. Bu nedenle, zamanla çalışmak için SQL'e başka bir veri türü eklendi . Şimdi türler şöyle görünür:

  • TARİH - tarihi saklar: yıl, ay, gün.
  • TIME - zamanı saklar: saat, dakika, saniye.
  • TIMESTAMP - zamanda belirli bir noktayı saklar: tarih, saat ve milisaniye.
  • ZAMAN DİLİMİ İLE ZAMAN BİLGİSİ - ZAMAN BİLGİSİ ve saat dilimi (bölge adı veya ofset).

İkinci olarak Java, küresel zaman yönetimi için DateTime API'sini tanıttı. Aşağıdaki sınıflara sahiptir:

  • Tarih ve saat :
    • Yerel Tarih
    • Yerel zaman
  • Tam an :
    • Java.time.Anında
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Saat dilimi ile saat :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Üçüncü ilginç nokta, birçok SQL istemcisinin zaten kendi yerel bölgelerinde bulunan sunucudan zaman almak istemesidir . Elbette zamanı anında dönüştürebilirsiniz, ancak bu uygun değildir ve hatalar vardır.

Örneğin, bugünün tüm görevlerini veritabanından almak istiyorum. SQL Server bunun için bir CURDATE() işlevine sahiptir. Sadece burada sunucu ABD'de ve ben Japonya'dayım. Ve "bugün" için değil, "bugün" için tüm kayıtları iade etmesini istiyorum.

Genel olarak, SQL sunucusunun farklı saat dilimlerindeki istemcilerle de akıllıca çalışabilmesi gerekir.

Modern problemler, modern çözümler gerektirir.

Prensip olarak, Java DateTime API'sinden yeni türler ve SQL'den türler kolayca eşlenebilir. DATE türünü Java'da temsil etmek için , JDK 8 DateTime API'sinden java.time.LocalDate sınıfını kullanmanız gerekir.

Veritabanındaki TIME türü, Java'daki iki türle temsil edilebilir: java.time.LocalTime ve java.time.OffsetTime . Karmaşık bir şey de yok.

Veritabanındaki TIMESTAMP türüyle temsil edilen belirli bir zaman noktası, Java'da 4 türle temsil edilebilir:

  • Java.time.Anında
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Son olarak, ZAMAN DİLİMİ İLE TIMESTAMP iki türle temsil edilebilir:

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

DateTime API'sine zaten aşina olduğunuz için bu konuyu hatırlamanız sizin için zor olmayacaktır :)

Bunu bir tablo şeklinde yazacağım, bu yüzden daha kolay olacak:

SQL TÜRÜ Java Tipi
TARİH java.time.LocalDate
ZAMAN java.time.LocalTime
java.time.OffsetTime
ZAMAN BİLGİSİ java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
ZAMAN DİLİMİYLE ZAMAN DÜŞÜNCESİ java.time.OffsetDateTime
_

tarihi almak

Senin için güzel bir haberim var. Uzun zamandır ilk. Bir java.sql Tarih türü döndüren getDate() yönteminin sınırlamasını aşabiliriz .

Mesele şu ki, nesnesonuç kümesibaşka ilginç bir yöntem var - getObject() . Bu yöntem iki parametre alır: bir sütun ve bir tür ve verilen türe dönüştürülen sütunun değerini döndürür. Yöntemin genel şekli aşağıdaki gibidir:

ClassName Name = getObject(column, ClassName);

Ve DATE türünü java.time.LocalDate türüne dönüştürmek istiyorsanız , şöyle bir şey yazmanız gerekir:

LocalDate localDate = results.getObject(4, LocalDate.class);

Ve genel olarak herhangi bir TIMESTAMP bir grup türe dönüştürülebilir:

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);

Önemli! Eski bir MySQL JDBC Sürücünüz varsa bu kod çalışmaz . Pom.xml'inizde yazılan veya proje ayarlarında Kitaplıklara eklenen "mysql-connector-java" sürümüne dikkat edin.

Bu arada, aynı şekilde, ilkel türler için null depolayamama sorununu da çözebilirsiniz. Bir tablo sütunu INT türündeyse, ondan null almanın birkaç yolu vardır. Aşağıdaki örneğe bakın:

Integer id1 = results.getObject(8, Integer.class);    	 // this will work
Integer id2 = results.getObject(8, int.class);                 //this will also work
int id3 = results.getObject(8,  Integer.class);            	//method will return null, JVM will throw NPE
int id4 = results.getObject(8,  int.class);                    	//method will return null, JVM will throw NPE

MySQL'de saat dilimi ayarı

MySQL ile de pek çok ilginç şey oldu. Bildiğiniz gibi MySQL bağlantısı oluştururken ona çeşitli parametreler ekleyebilirsiniz :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

Bu nedenle, MySQL'de saat dilimleriyle çalışmak için üç parametre eklendi. Sunucuya bağlantı kurduğunuzda bu parametreleri iletebilirsiniz.

Aşağıda onlarla bir tablo vereceğim:

Parametre Değerler Varsayılan değer
bağlantıZaman Dilimi YEREL | SUNUCU | kullanıcı bölgesi SUNUCU
forceConnectionTimeZoneToSession doğru | YANLIŞ doğru
korumakAnında doğru | YANLIŞ YANLIŞ

ConnectionTimeZone parametresini kullanarak , tüm isteklerin yürütüleceği saat dilimini (zaman dilimini) seçiyoruz. İstemci açısından, sunucu belirtilen saat diliminde çalışıyor.

forceConnectionTimeZoneToSession parametresi, oturum time_zone değişkeninin yoksayılmasına ve ConnectionTimeZone ile değiştirilmesine neden olur.

Son olarak, saveInstants parametresi , JVM'nin timeZone ve connectionTimeZone arasındaki tam zaman dönüşümünü kontrol eder.

En yaygın yapılandırmalar şunlardır:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - useLegacyDatetimeCode=true ile eski MySQL JDBC sürücüsü sürüm 5.1'e karşılık gelir.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true, tarih ve saat değerlerini işlemenin en doğal yolunu sağlayan yeni bir moddur.

  • connectionTimeZone=SERVER &protectInstants=true - useLegacyDatetimeCode=false ile eski MySQL JDBC sürücüsü sürüm 5.1'e karşılık gelir.

  • ConnectionTimeZone=user_defined & ProtectInstants=true - CET/CEST gibi genel bir kısaltma olarak ayarlandığı için sunucunun saat diliminin bağlayıcı tarafından tanınamadığı durumun üstesinden gelmeye yardımcı olur.

Evet, tarihler ilginç bir konudur ve onlarla ilgili birçok sorun vardır. Söylediği gibi: korkutucu, elbette, ama ben de kızgın değilim! :)