Текущото състояние на нещата във времето
От времето, когато JDBC е изобретен и неговите интерфейси са стандартизирани, са изминали 20 години и през това време много неща са се променor.
Първо, светът стана глобален и сега един сървър може да обслужва потребители от цял свят. Скоростта на интернет се повиши. Следователно към SQL беше добавен друг тип данни за работа с времето. Сега типовете изглеждат така:
- ДАТА - съхранява датата: година, месец, ден.
- ВРЕМЕ - съхранява време: часове, minutesи, секунди.
- TIMESTAMP - съхранява конкретна точка от времето: дата, час и мorсекунди.
- TIMESTAMP WITH TIME ZONE - TIMESTAMP и часова зона (име на зона or отместване).
Второ, Java представи DateTime API за глобално управление на времето. Има следните класове:
- Дата и час :
- Местна дата
- Местно време
- Точен момент :
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
- Време с часова зона :
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Третият интересен момент е, че много SQL клиенти биха искали да получават време от сървъра, който вече е в тяхната локална зона . Разбира се, можете да конвертирате времето в движение, но не е удобно и има грешки.
Например, искам да взема всички задачи за днес от базата данни. SQL Server има функция CURDATE() за това. Само тук сървърът е в САЩ, а аз съм в Япония. И бих искал той да върне всички записи за „моето днес“, а не „неговото днес“.
Като цяло, SQL сървърът също трябва да може да работи интелигентно с клиенти в различни часови зони.
Съвременните проблеми изискват модерни решения
По принцип новите типове от Java DateTime API и типовете от SQL могат да бъдат удобно картографирани. За да представите типа DATE в Java, трябва да използвате класа java.time.LocalDate от JDK 8 DateTime API.
Типът TIME от базата данни може да бъде представен от два типа от Java: java.time.LocalTime и java.time.OffsetTime . Нищо сложно също.
Конкретен момент от време, представен от типа TIMESTAMP в базата данни, може да бъде представен в Java чрез 4 типа:
- java.time.Instant
- java.time.LocalDateTime
- java.time.OffsetDateTime
- java.time.ZonedDateTime
И накрая, TIMESTAMP WITH TIME ZONE може да бъде представен от два типа:
- java.time.OffsetDateTime
- java.time.ZonedDateTime
Тъй като вече сте запознати с API на DateTime, запомнянето на този въпрос няма да е трудно за вас :)
Ще го напиша под формата на table, така че ще бъде по-лесно:
SQL ТИП | Тип Java |
---|---|
ДАТА | java.time.LocalDate |
ВРЕМЕ | java.time.LocalTime java.time.OffsetTime |
КЛАПОТО ЗА ЧАС | java.time.Instant java.time.LocalDateTime java.time.OffsetDateTime java.time.ZonedDateTime |
ЧАСОВ ПЕЧАТ С ЧАСОВА ЗОНА | java.time.OffsetDateTime _ |
Получаване на датата
Имам добра новина за вас. Първо от много време. Можем да заобиколим ограничението на метода getDate() , който връща java.sql тип Дата.
Въпросът е, че обектътнабор от резултатиима още един интересен метод - getObject() . Този метод приема два параметъра: колона и тип и връща стойността на колоната, преобразувана в дадения тип. Общата форма на метода е следната:
ClassName Name = getObject(column, ClassName);
И ако искате да конвертирате типа DATE в типа java.time.LocalDate , тогава трябва да напишете нещо като:
LocalDate localDate = results.getObject(4, LocalDate.class);
И всеки TIMESTAMP като цяло може да бъде преобразуван в куп типове:
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);
важно! Този code няма да работи, ако имате остарял MySQL JDBC драйвер . Обърнете внимание на versionта на "mysql-connector-java", написана във вашия pom.xml or добавена към библиотеките в настройките на проекта.
Между другото, по същия начин можете да заобиколите невъзможността да съхранявате null за примитивни типове. Ако колона на table е от тип INT, тогава има няколко начина да получите нула от нея. Вижте примера по-долу:
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
С MySQL също се случиха много интересни неща. Както знаете, когато създавате MySQL връзка, можете да добавите различни параметри към нея :mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning
И така, добавени са три параметъра за работа с часови зони в MySQL. Можете да подадете тези параметри, когато установите връзка със сървъра.
По-долу ще дам table с тях:
Параметър | Стойности | Стойност по подразбиране |
---|---|---|
връзка TimeZone | МЕСТЕН | СЪРВЪР | потребителска зона | СЪРВЪР |
forceConnectionTimeZoneToSession | вярно | невярно | вярно |
SaveInstants | вярно | невярно | невярно |
С помощта на параметъра connectionTimeZone избираме часовата зона (часова зона), в която ще се изпълняват всички заявки. От гледна точка на клиента, сървърът работи в определената часова зона.
Параметърът forceConnectionTimeZoneToSession кара променливата time_zone на сесията да бъде игнорирана и заменена с connectionTimeZone.
И накрая, параметърът SaveInstants контролира преобразуването на точното време между timeZone на JVM и connectionTimeZone.
Най-често срещаните конфигурации са:
-
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - съответства на стария MySQL JDBC драйвер version 5.1 с useLegacyDatetimeCode=true.
-
connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true е нов режим, който осигурява най-естествения начин за обработка на стойностите за дата и час.
-
connectionTimeZone=SERVER & SaveInstants=true - Съответства на стария MySQL JDBC драйвер version 5.1 с useLegacyDatetimeCode=false.
-
connectionTimeZone=user_defined & SaveInstants=true - Помага за преодоляване на ситуацията, при която часовата зона на сървъра не може да бъде разпозната от конектора, тъй като е зададена като общо съкращение като CET/CEST.
Да, датите са интересна тема и има много проблеми с тях. Както се казва: страшно е, разбира се, но и аз не се сърдя! :)
GO TO FULL VERSION