Почему я получаю даты обратно один раз при использовании JOOQ? - PullRequest
1 голос
/ 05 апреля 2019

Мы используем jOOQ для связи с базой данных MySQL, содержащей эту таблицу:

CREATE TABLE daily_sessions
(
  session_id INT AUTO_INCREMENT NOT NULL,
  user_id    VARCHAR(45)        NULL,
  day        date               NULL,
  CONSTRAINT PK_DAILY_SESSIONS PRIMARY KEY (session_id)
);

Мы включили поддержку типов JSR-310, поэтому мы используем LocalDate на Java / Kotlinсторона, чтобы отобразить это.

Мы видим, что поле day извлекается со смещением в один день.Операторы вставки и выбора, записанные в журнале jOOQ, по-видимому, указывают на то, что при связывании параметров SQL он работает правильно, но когда возвращается результат, он показывает днем ​​ранее:

2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.i.DefaultConnectionProvider - setting auto commit      : false
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.tools.LoggerListener  - Executing query          : select `daily_sessions`.`session_id`, `daily_sessions`.`user_id`, `daily_sessions`.`day` from `daily_sessions` where (`daily_sessions`.`user_id` = ? and `daily_sessions`.`day` = ?)
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.tools.LoggerListener  - -> with bind values      : select `daily_sessions`.`session_id`, `daily_sessions`.`user_id`, `daily_sessions`.`day` from `daily_sessions` where (`daily_sessions`.`user_id` = '87a09702-0d6b-485c-895c-986f238e1d30' and `daily_sessions`.`day` = {d '2011-11-11'})
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.tools.LoggerListener  - Fetched result           : +----------+------------------------------------+----------+
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.tools.LoggerListener  -                          : |session_id|user_id                             |day       |
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.tools.LoggerListener  -                          : +----------+------------------------------------+----------+
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.tools.LoggerListener  -                          : |        13|87a09702-0d6b-485c-895c-986f238e1d30|2011-11-10|
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.tools.LoggerListener  -                          : +----------+------------------------------------+----------+
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.tools.LoggerListener  - Fetched row(s)           : 1
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.i.DefaultConnectionProvider - commit                   
2019-04-05 09:32:08 [Gax-20    ] DEBUG o.j.i.DefaultConnectionProvider - setting auto commit      : true
2019-04-05 09:32:08 [Gax-20    ] DEBUG c.z.hikari.pool.PoolBase  - HikariPool-1 - Reset (isolation) on connection com.mysql.cj.jdbc.ConnectionImpl@4af95547

Обратите внимание, как фильтр выбора включается 2011-11-11, но таблица результатов показывает 2011-11-10.

Это тест, выполненный на моем локальном компьютере (UTC + 10), против стандартного mysql образа Docker, работающего также локально.

Несмотря на использование DATE, я предполагаю, что мы столкнулись с некоторой проблемой часового пояса, но я не могу воспроизвести проблему, говоря непосредственно о JDBC.Я попытался запустить его в той же настройке, в которой запускаются другие тесты:

@Test
fun testDateColumn() {
    DriverManager.getConnection("jdbc:mysql://localhost:8890/rewards-test", "root", "").use { con ->
        con.createStatement().use { stmt ->
            stmt.execute("insert into `daily_sessions` (`user_id`, `day`) values ('a20add98-5a93-417f-a771-848757b2b1f8', {d '2011-11-11'})")
        }
        con.createStatement().use { stmt ->
            stmt.executeQuery("select `daily_sessions`.`session_id`, `daily_sessions`.`user_id`, `daily_sessions`.`day` from `daily_sessions` where (`daily_sessions`.`user_id` = 'a20add98-5a93-417f-a771-848757b2b1f8' and `daily_sessions`.`day` = {d '2011-11-11'})").use { rs ->
                while (rs.next()) {
                    println("${rs.getString(3)} - ${rs.getDate(3)}")
                }
            }
        }
    }
}

Этот код выдает ожидаемый результат.Операторы SQL - это прямые копии из журналов jOOQ.Должно быть что-то еще, что jOOQ делает, чего я не понимаю.

Нужно ли как-то настраивать часовые пояса в jOOQ?Или я что-то пропустил?

Обновление

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

@Test
fun testDateColumn() {
    DriverManager.getConnection("jdbc:mysql://localhost:8890/rewards-test", "root", "").use { con ->
        con.prepareStatement("insert into `daily_sessions` (`user_id`, `day`) values (?, ?)").use { ps ->
            ps.setString(1, "a20add98-5a93-417f-a771-848757b2b1f8")
            ps.setDate(2, Date.valueOf(LocalDate.of(2011, 11, 11)))
            ps.execute()
        }
        con.prepareStatement("select `daily_sessions`.`session_id`, `daily_sessions`.`user_id`, `daily_sessions`.`day` from `daily_sessions` where (`daily_sessions`.`user_id` = ? and `daily_sessions`.`day` = ?)").use { ps ->
            ps.setString(1, "a20add98-5a93-417f-a771-848757b2b1f8")
            ps.setDate(2, Date.valueOf(LocalDate.of(2011, 11, 11)))
            ps.executeQuery().use { rs ->
                    while (rs.next()) {
                        println("${rs.getString(3)} - ${rs.getDate(3)}")
                    }
                }
        }
    }
}

Это действительно дает неправильные результаты, вывод 2011-11-10 для вариантов строки и даты.Кажется, в JDBC есть кое-что, чего я не понимаю.

Обновление 2

Приведенный выше код можно исправить, передав в качестве третьего экземпляр по умолчанию java.util.CalendarПараметр для метода setDate, т.е. замена обоих описанных выше случаев на:

ps.setDate(2, Date.valueOf(LocalDate.of(2011, 11, 11)), Calendar.getInstance())

Используя это, мы видим ожидаемый результат, тогда как обычная версия без третьего параметра - нет.

JavaDoc метода setDate говорит, что отсутствие объекта Calendar приведет к использованию часового пояса виртуальной машины, который выглядит точно так же , определение Calendar.getInstance () задает Кажется, что ничего не должно измениться.

1 Ответ

1 голос
/ 09 апреля 2019

Это оказалось известной ошибкой в ​​драйвере JDBC MySQL .Мое исправление состояло в том, чтобы вернуться к гораздо более старой версии, которая предшествовала проблеме.

...