Сохранение дробных секунд в тип данных TIME в БД с использованием JOOQ - PullRequest
4 голосов
/ 26 июня 2019

Мне нужно хранить данные из внешнего API в MariaDB.Одно из полей имеет вид java.time.LocalTime и сохраняется с использованием типа TIME.Может содержать доли секунд.Я использую JOOQ для построения / выполнения SQL.

Поле БД создается с использованием TIME(6), и данные там правильно отображаются как «чч: мм: сс.сссссс».Однако всякий раз, когда я сохраняю данные из своего приложения, дробная часть обнуляется.Например: 12:34:56.123456 -> 12:34:56.000000

Я понимаю, что это связано с тем, что JOOQ использует java.sql.Time внутри, и поскольку он расширяет java.util.Date, часть точности теряется.Я пытаюсь найти способ обойти эту проблему, чтобы я все еще мог сохранять время по мере их поступления.

Что я пробовал:

  1. Использованиеcustom org.jooq.Converter, который преобразует между java.sql.Time и java.time.LocalTime, но в отличие от значения по умолчанию org.jooq.impl.TimeToLocalTimeConverter, сохраняет миллисекундную часть объекта времени.Это позволяет мне сохранять и извлекать значения с точностью до миллисекунды (3 места после запятой).

  2. Из некоторых ресурсов в Интернете казалось, что можно использовать LocalTime и LocalDateTime напрямую с новыми драйверами JDBC.Чтобы попробовать это, я попытался использовать org.jooq.Converter, который конвертирует из java.time.LocalTime в java.time.LocalTime, просто пропуская объекты.Я надеялся, что JOOQ просто использует этот конвертер и напрямую передает LocalTime в БД, но, к сожалению, он не работает так.Значение по-прежнему обрабатывается реализацией по умолчанию, а дробная часть данных теряется.

  3. Чтобы пройти мимо функций JOOQ по умолчанию, я попытался создать пользовательский org.jooq.Binding, которыйбудет использовать входящий объект напрямую.Однако когда я попытался сделать это, используя в качестве основы пользовательский пример привязки JOOQ , я не смог реализовать необходимые методы.Например, где пример имеет:

    public void get(BindingGetStatementContext<JsonElement> ctx) throws SQLException {
        ctx.convert(converter()).value(ctx.statement().getString(ctx.index()));
    }

... Мне нужно сделать что-то вроде:

    public void get(BindingGetStatementContext<LocalTime> ctx) throws SQLException {
        ctx.convert(converter()).value(ctx.statement().getLocalTime(ctx.index()));
    }

Но java.sql.CallableStatement не имеет такого метода.Неужели я не понимаю, что должно быть возможно?

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

1 Ответ

1 голос
/ 28 июня 2019

Вы не можете решить эту проблему, используя Converter, поскольку jOOQ будет продолжать использовать JDBC типа java.sql.Time за кадром.Вам нужно реализовать свой Binding.Если ваш драйвер JDBC поддерживает типы JSR 310, метод, с которым у вас возникли проблемы, должен выглядеть следующим образом:

public void get(BindingGetStatementContext<LocalTime> ctx) throws SQLException {
    ctx.value(ctx.statement().getObject(ctx.index(), LocalTime.class));
}

Обратите внимание, что в этом случае вам не следует использовать Converter, потому что выуже убедившись, что тип Binding<T, U> <U> (где T = java.sql.Time и U = java.time.LocalTime) правильно выбран из JDBC.

...