Dagens tilstand over tid
Siden tiden da JDBC ble oppfunnet og grensesnittene ble standardisert, har det gått 20 år, og i løpet av denne tiden har mye endret seg.
For det første har verden blitt global og nå kan én server betjene brukere fra hele verden. Internett-hastigheten er oppe. Derfor ble en annen datatype lagt til SQL for å jobbe med tiden. Nå ser typene slik ut:
- DATO - lagrer datoen: år, måned, dag.
- TID - lagrer tid: timer, minutter, sekunder.
- TIMESTAMP - lagrer et bestemt tidspunkt: dato, klokkeslett og millisekunder.
- TIDSSTEMPEL MED TIDSSONE - TIDSSTIMPEL og tidssone (sonenavn eller forskyvning).
For det andre introduserte Java DateTime API for global tidsstyring. Den har følgende klasser:
- Dato og tid :
- LocalDate
- Lokal tid
- Nøyaktig øyeblikk :
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
- Tid med tidssone :
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Det tredje interessante poenget er at mange SQL-klienter ønsker å motta tid fra serveren allerede i sin lokale sone . Selvfølgelig kan du konvertere tid på farten, men det er ikke praktisk, og det er feil.
For eksempel vil jeg hente alle oppgavene for i dag fra databasen. SQL Server har en CURDATE() -funksjon for dette. Bare her er serveren i USA, og jeg er i Japan. Og jeg vil at han skal returnere alle platene for "min i dag", og ikke "hans i dag".
Generelt må SQL-serveren også kunne jobbe smart med klienter i ulike tidssoner.
Moderne problemer krever moderne løsninger
I prinsippet kan nye typer fra Java DateTime API og typer fra SQL enkelt kartlegges. For å representere DATE- typen i Java, må du bruke klassen java.time.LocalDate fra JDK 8 DateTime API.
TIME-typen fra databasen kan representeres av to typer fra Java: java.time.LocalTime og java.time.OffsetTime . Ikke noe komplisert heller.
Et spesifikt tidspunkt, representert av TIMESTAMP -typen i databasen, kan representeres i Java med 4 typer:
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Og til slutt kan TIMESTAMP WITH TIME SONE representeres av to typer:
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Siden du allerede er kjent med DateTime API, vil det ikke være vanskelig for deg å huske denne saken :)
Jeg vil skrive det i form av en tabell, så det blir enklere:
SQL TYPE | Java Type |
---|---|
DATO | java.time.LocalDate |
TID | java.time.LocalTime java.time.OffsetTime |
TIDSSTIMPEL | java.time.Instant java.time.LocalDateTime java.time.OffsetDateTime java.time.ZonedDateTime |
TIDSSTIMPEL MED TIDSSONE | java.time.OffsetDateTime _ |
Får datoen
Jeg har gode nyheter til deg. Først på lenge. Vi kan komme rundt begrensningen til getDate()- metoden , som returnerer en java.sql-datotype.
Poenget er at objektetresultatsettdet er en annen interessant metode - getObject() . Denne metoden tar to parametere: en kolonne og en type, og returnerer verdien av kolonnen konvertert til den gitte typen. Den generelle formen for metoden er som følger:
ClassName Name = getObject(column, ClassName);
Og hvis du vil konvertere DATO- typen til java.time.LocalDate- typen , må du skrive noe sånt som:
LocalDate localDate = results.getObject(4, LocalDate.class);
Og et hvilket som helst TIMESTAMP generelt kan konverteres til en rekke typer:
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);
Viktig! Denne koden vil ikke fungere hvis du har en utdatert MySQL JDBC-driver . Vær oppmerksom på versjonen av "mysql-connector-java" skrevet i din pom.xml, eller lagt til bibliotekene i prosjektinnstillingene.
Forresten, på samme måte kan du komme deg rundt manglende evne til å lagre null for primitive typer. Hvis en tabellkolonne er av typen INT, er det et par måter å få null fra den. Se eksempel nedenfor:
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
Tidssoneinnstilling i MySQL
Mye interessante ting skjedde også med MySQL. Som du vet, når du oppretter en MySQL-tilkobling, kan du legge til forskjellige parametere til den :mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning
Så tre parametere er lagt til for å fungere med tidssoner i MySQL. Du kan sende disse parameterne når du oppretter en tilkobling til serveren.
Nedenfor vil jeg gi en tabell med dem:
Parameter | Verdier | Standardverdi |
---|---|---|
tilkoblingstidssone | LOKAL | SERVER | brukersone | SERVER |
forceConnectionTimeZoneToSession | sant | falsk | ekte |
bevarInstants | sant | falsk | falsk |
Ved å bruke parameteren connectionTimeZone velger vi tidssonen (tidssonen) der alle forespørsler skal utføres. Fra klientens synspunkt kjører serveren i den angitte tidssonen.
ForceConnectionTimeZoneToSession -parameteren fører til at session time_zone-variabelen ignoreres og erstattes med connectionTimeZone.
Til slutt kontrollerer preserveInstants- parameteren den nøyaktige tidskonverteringen mellom JVMs tidssone og connectionTimeZone.
De vanligste konfigurasjonene er:
-
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - tilsvarer den gamle MySQL JDBC-driveren versjon 5.1 med useLegacyDatetimeCode=true.
-
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true er en ny modus som gir den mest naturlige måten å håndtere dato- og tidsverdier på.
-
connectionTimeZone=SERVER & preserveInstants=true - Tilsvarer den gamle MySQL JDBC-driveren versjon 5.1 med useLegacyDatetimeCode=false.
-
connectionTimeZone=user_defined & preserveInstants=true - Hjelper med å overvinne situasjonen der serverens tidssone ikke kan gjenkjennes av koblingen fordi den er satt som en generisk forkortelse som CET/CEST.
Ja, datoer er et interessant tema, og det er mange problemer med dem. Som det sies: det er skummelt, selvfølgelig, men jeg er heller ikke forbanna! :)
GO TO FULL VERSION