Кровавый случай, вызванный точностью метки времени MySQL

Java

написать впереди

Недавно в своей работе я столкнулся с двумя проблемами, связанными с временными метками mysql: во-первых, точность mysql-connector-java и msyql несовместима, что приводит к тому, что данные не могут быть найдены, во-вторых, ошибка часового пояса сервера приложений приводит к тому, что данные чтобы не допрашивали. В этой статье я надеюсь ответить на несколько вопросов о временных метках в mysql:

  1. Почему точность DATETIME в mysql поддерживается только в секундах?
  2. Связан ли тип DATETIME в mysql с часовым поясом?
  3. Когда mysql создает таблицу, как выбрать поле, представляющее время?

Пример проблемы с точностью DATETIME

Некоторое время назад версия mysql-connector-java ответственного приложения была обновлена ​​с 5.1.16 до 5.1.30.При выполнении функциональной регрессии было обнаружено, что данные времени выполнения вариантов использования с использованием SQL, аналогичные приведенным выше, будут отсутствует, что приводит к возникновению проблемы с функцией.

Учитывая, что в приложении, за которое я отвечаю, есть функция, которая должна использовать SQL, как показано ниже, то есть использовать метку времени в качестве условия запроса для запроса всех данных после определенной метки времени.

После расследования было обнаружено, что: mysql-connector-java отбрасывает точность после секунды, прежде чем передать ее на сервер MySQL до 5.1.23. Бывает, что точность DATETIME в используемой нами версии mysql составляет секунды; когда я обновить mysql-connector-java После 5.1.30, когда метка времени передается из приложения java на сервер MySQL через mysql-connector-java, миллисекунды не будут отброшены.С точки зрения mysql-connector-java, ошибка был исправлен, но для моего приложения это вызвало ошибку.

Если вы столкнетесь с этой проблемой, как вы ее исправите?

В то время мы думали о трех вариантах:

  • Измените тип параметра timestamp в интерфейсе Mapper mybatis с java.util.Date на java.sql.Date;

  • Перед переходом в интерфейс Mapper входящая метка времени положительна в секундах, код выглядит следующим образом

    22.png

  • Перед запросом уменьшите входящую метку времени на 1 секунду;

После проверки схема 1 будет, объект java.sql.Date, переданный java.util.Date, потеряет всю точность после даты, что приведет к запросу большего количества ненужных данных; схема 3 возможна, но может быть или еще два данных, возможна и схема 2, что равносильно компенсации характеристик mysql-connector-java из кода. В итоге выбрал вариант 2.

Повторение случая

Используйте homebrew для установки MySQL, версия 8.0.15.После установки создайте таблицу для хранения информации о пользователе.SQL выглядит следующим образом:

55.png

Используйте spirngboot + mybatis в качестве среды разработки, определите пользовательскую сущность, код выглядит следующим образом:

44.png

Определите Mapper, соответствующий объекту, код выглядит следующим образом:

33.png

Установите конфигурацию, связанную с подключением к mysql, код выглядит следующим образом:

image.png

Напишите тестовый код, сначала вставьте часть данных, а затем используйте метку времени в качестве условия запроса для запроса, код выглядит следующим образом:

image.png

Запуск одного теста, как мы предполагали, не запрашивал данные, и результаты следующие:

image.png

Затем измените код и используйте приведенный выше код, чтобы сделать отметку времени запроса положительной в секундах.Код выглядит следующим образом:

image.png

Запустите одиночный тест еще раз, как мы и предполагали, на этот раз данные можно запросить.

Однако вот небольшой эпизод: когда я впервые проектировал таблицу, оператор SQL, который я использовал, был следующим:

SQL_2.png

Как бы вы ни были умны, здесь datetime уже поддерживает меньшую точность времени после десятичной точки и поддерживает до 6 цифр, то есть может поддерживать до тонкого уровня. Когда была представлена ​​эта функция?Я проверил [официальную документацию MySQL][9] и обнаружил, что эта функция поддерживается после MySQL 5.6.4.

image.png

Резюме очков знаний

После предыдущего фактического анализа случая и повторения случая читатель должен иметь определенное представление о типе DATETIME в mysql.Давайте посмотрим на него со мной и какой опыт мы можем извлечь из этого случая.

  1. Версию mysql-connector-java и версию mysql необходимо использовать вместе, например версию до 5.6.4, лучше не использовать версию mysql-connector-java после 5.1.23, иначе на этот раз мы можем столкнуться с возникшими проблемами.
  2. Типы полей, используемые для представления времени в MySQL: DATE, DATETIME, TIMESTAMP. Они имеют сходство, и каждый из них имеет свои характеристики. Я резюмирую таблицу следующим образом:
    image.png
  3. Тип DATETIME хранится как целое число в формате «ГГГГММДДЧЧММСС» в MySQL, независимо от часового пояса, и занимает 8 байтов пространства;
  4. Тип TIMESTAMP может сохранить гораздо меньший временной диапазон, а отображаемое значение зависит от часового пояса.Сервер MySQL, операционная система и клиентское соединение имеют настройки часового пояса.
  5. Как правило, рекомендуется использовать DATETIME в качестве поля метки времени, и не рекомендуется использовать тип bigint для хранения времени.
  6. При разработке следует стараться избегать использования временных меток в качестве условий запроса.Если вы должны их использовать, вам необходимо полностью учитывать точность MySQL и точность параметров запроса.

использованная литература

  1. Dev.MySQL.com/doc/Furious/…
  2. «Высокопроизводительный MySQL»

В этом выпуске основное внимание уделяется таким темам, как серверные технологии, устранение неполадок и оптимизация JVM, вопросы на собеседованиях по Java, личностный рост и самоуправление, а читателям предлагается опыт работы и роста передовых разработчиков. .

javaadu