JavaRush /Курстар /All lectures for KY purposes /Убакыт менен иштөө

Убакыт менен иштөө

All lectures for KY purposes
Деңгээл , Сабак
жеткиликтүү

Заманбап убакыт маселелери

JDBC ойлоп табылып, анын интерфейстери стандартташтырылган күндөн бери 20 жыл өтүптүр, жана бул убакыт ичинде көп нерсе өзгөрдү.

Биринчи кезекте, дүйнө глобалдык болуп калды жана азыр бир сервер дүйнөнүн ар кайсы бурчунан келген колдонуучуларды тейлей алат. Интернеттин ылдамдыгы чечип койду. Ошондуктан SQL'ге убакыт менен иштөө үчүн дагы бир маалымат тиби кошулган. Азыр типтер мындай көрүнөт:

  • DATE – жыл, ай, күндү сактайт.
  • TIME – саат, мүнөт, секундаларды сактайт.
  • TIMESTAMP – убакыттын так учурларын сактайт: дата, убакыт жана миллисекундалар.
  • TIMESTAMP WITH TIME ZONE – TIMESTAMP жана убакыт алкагы (зонанын аталышы же жылышы).

Экинчи, Java'да глобалдык убакыт менен иштөө үчүн DateTime API пайда болду. Анда мындай класстар бар:

  • Дата жана убакыт:
    • LocalDate
    • LocalTime
  • Так учурлар:
    • java.time.Instant
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Убакыт алкагы менен убакыт:
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Үчүнчү кызыктуу учур - көптөгөн SQL-кардарлары серверден убакытты өздөрүнүн жергиликтүү зонасында алууну каалашат. Убакытты дароо өзгөртүү албетте мүмкүн, бирок бул ыңгайсыз, кээде каталар да болушу мүмкүн.

Мисалы, мен базадан бүгүнкү бардык тапшырмаларды алуу керек. SQL-сервердин CURDATE() функциясы бар. Тек гана сервер АКШда турат, мен болсо Японияда. Жана ал мага “менин бүгүнүмдү” кайтарса жакшы болмок, анын “бүгүнү” эмес.

Жалпысынан, SQL-сервер да ар кандай убактылы зоналардагы кардарлар менен акылдуу иштей алышы керек.

Заманбап маселелер заманбап чечимдерди талап кылат

Маалыматтын жаңы типтери Java DateTime API жана SQL типтери менен ыңгайлуу салыштырылышы мүмкүн. Тип DATEти Java'да көрсөтүү үчүн JDK 8 DateTime API'дагы java.time.LocalDate классын колдонуу керек.

TIME базасындагы тип эки Java типи менен көрсөтүлүшү мүмкүн: java.time.LocalTime жана java.time.OffsetTime. Бул да кыйын эмес.

Так убакыттын учурлары, базадагы TIMESTAMP типи менен көрсөтүлүшү мүмкүн болгон 4 тип:

  • java.time.Instant
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Акыры, TIMESTAMP WITH TIME ZONE эки тип менен көрсөтүлүшү мүмкүн:

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

Дата жана убакыт менен иштөө жаатында жаңылыктар менен тааныш болуп калганың үчүн, буларды эс тутуу оңой болот :)

SQL TYPE жана Java Type түрлөрүн кичинекей таблицада кыстарсам болот:

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

Датаны алуу

Сен үчүн жакшы жаңылыгым бар. Көптөн бери биринчи. getDate() методунун чектөөсүн айланып өтө алабыз, ал java.sql Date типин кайтарат.

ResultSet объектинде дагы кызыктуу метод бар — getObject(). Бул метод эки параметрди кабыл алат: колонканы жана типти, жана колонканын маанисин көрсөтүлгөн типке өзгөртүп кайтарат. Методдун жалпы түрү мындай:


ИмяКласса имя = getObject(column, ИмяКласса);

Эгер сен 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);

Мүмкүн эмес! Эскирген MySQL JDBC Driver колдонулганда бул код иштебей калат. Версиясын текшерип көрүү керек “mysql-connector-java”, ал сенin pom.xml'да жазылып же Libraries папканын жоболорунда кошулушу мүмкүн.

Ошондой эле, примитивдүү типтерде null сактоо мүмкүн эмес болсо, ушул ыкма менен айланып өтүүгө болот. Эгерде таблица колонкасы INT типинде болсо, анда null алуу үчүн бир нече жол бар. Төмөндө карап көр:


  Integer id1 = results.getObject(8, Integer.class);    	 //бұлай жұмыс істейді
  Integer id2 = results.getObject(8, int.class);                 //бұлай да жұмыс істейді
  int id3 = results.getObject(8,  Integer.class);            	//метод возвращает null, JVM кидає NPE
  int id4 = results.getObject(8,  int.class);                    	//метод возвращает null, JVM кидає NPE

MySQLде убакыт алкагын орнотуу

MySQL менен дагы кызыктуу нерселер болду. Билгендей, MySQL менен туташуу түзүлгөндө ар кандай параметрлерди кошуу мүмкүн:
mysql://localhost:3306/db_scheme?имя=значение&имя=значение

Убакыт алкактары менен иштөө үчүн MySQL'ге үч параметр кошулган. Бул параметрлерди сервер менен туташуу түзгөндө өтүүгө болот.

Төмөндө алардын таблицасы келтирилген:

Параметр Значения Значение по умолчанию
connectionTimeZone LOCAL | SERVER | user-zone SERVER
forceConnectionTimeZoneToSession true | false true
preserveInstants true | false false

connectionTimeZone параметри аркылуу бардык суроолор аткарылуучу убакыт алкагын тандайбыз. Кардардын көз карашынан караганда, сервер көрсөткөн убакыт зонасында иштейт.

forceConnectionTimeZoneToSession параметри time_zone сессиясынын өзгөрмөсүн көз жаздымда калтырып, аны connectionTimeZone менен алмаштырат.

Акыры, preserveInstants параметри JVM timeZone жана connectionTimeZone ортосунда так убакыт учурларын өзгөртүүнү башкарат.

Эң көп колдонулуучу конфигурациялар төмөнкүдөй:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false — MySQL JDBC драйверинин 5.1 версиясына туура келет, анын ичиндеги useLegacyDatetimeCode=true параметри.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true — жаңы режим, даталар менен убакыт маанилерин эң табигый жол менен иштетүүнү камсыз кылат.

  • connectionTimeZone=SERVER & preserveInstants=true — MySQL JDBC драйверинин 5.1 версиясына туура келет, анын ичиндеги useLegacyDatetimeCode=false параметри.

  • connectionTimeZone=user_defined & preserveInstants=true — сервердин убакыт алкагын коннектор тааный албай турган учурда жардам берет, анткени ал жалпы кыскартуу катары орнотулган, мисалы CET/CEST.

Ооба, даталар — кызыктуу жана көп маселелерди алып келүүчү тема. Аталар айткандай: бул үрөйдү учурса дагы, мен коркуп калбайм! :)

Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION