Обработка закрытых соединений JDBC

Я хочу автоматически переподключиться и повторно отправить последний SQL-запрос, если соединение закрыто (например, на сервере БД, а не потому, что я его закрою).

Я знаю, что мог бы сделать connection.isValid() (что просто SELECT 1 в большинстве реализаций драйверов) перед отправкой каждого запроса, но это расточительно. Я добавлю задержку туда-обратно к каждому из моих запросов.

Я хотел что-то вроде:

  • Отправляет запрос в базу
  • Если соединение не работает, переподключитесь и повторно отправьте тот же запрос.
  • Если не удается восстановить соединение, закройте соединение Exception.

Есть ли рекомендации по этому поводу? Я не могу представить, что я первый, кто хочет что-то подобное.

Я думаю о том, чтобы сделать обертку вокруг моего драйвера java.sql.Connection и запустить этот алгоритм за кулисами, но если что-то еще есть, я был бы признателен, если бы мне не пришлось изобретать колесо (я пытался погуглить, но ничего не нашел) .

PS: мне не нужен пул соединений, потому что я буду использовать его внутри экземпляра AWS Lambda, и все известные мне пулы соединений будут просто запускаться isValid перед каждым запросом.

Очаровательный. Мой совет: просто запускайте isValid перед каждым запросом. Попытка обнаружения постфактум будет хуже.

Elliott Frisch 26.03.2019 01:56

Преодолейте свое отвращение и используйте пул соединений, например. Апач ДБКП. Обо всем этом позаботится за вас и нет, вызывая isValid() перед каждым запросом, но обычно отправляя SELECT 1 в базу данных. Совет запускать isValid() перед каждым запросом — плохая практика: это равносильно попытке предсказать будущее. Соединение все еще может не работать после этого, и вам все равно придется иметь дело с этим. @ElliottFrisch

user207421 26.03.2019 02:02

@user207421 user207421 Мммм, обычно isValid() использует SELECT 1 против базы данных. И это также метод, который пул соединений будет использовать для проверки соединения (но я согласен с вами, что лучше позволить пулу соединений сделать это за вас).

Elliott Frisch 26.03.2019 02:06

@ user207421 большинство реализаций драйверов JDBC вызывают SELECT 1 внутри isValid()

Michel Feinstein 26.03.2019 02:06

Я буду запускать это внутри AWS Lambda, чем меньше у меня библиотек, тем лучше для холодного запуска. Кроме того, экземпляры AWS Lambda могут иметь только 1 соединение, поэтому это будет пул соединений только для 1 соединения... так что это похоже на тяжелое решение для конкретной проблемы.

Michel Feinstein 26.03.2019 02:08

Попытка протестировать после, который вы сделали для своего запроса, по-прежнему будет стоить дороже (как во время выполнения, так и в вашей собственной реализации).

Elliott Frisch 26.03.2019 02:12

Эта проблема очень связана с AWS Lambda, потому что экземпляр Lambda переходит в спящий режим после выполнения своего вызова. Как только появится новый вызов, Lambda будет разбужена, и соединение, которое я создал и кэшировал (поскольку для создания соединения требуется некоторое время, и мы платим за время в Lambda), может быть уже отключено.

Michel Feinstein 26.03.2019 02:12

@ElliottFrisch, не могли бы вы подробнее рассказать, почему это будет стоить дороже? Насколько я вижу, в тот момент, когда я попытаюсь выполнить запрос с отключенным соединением, произойдет сбой (столько же времени, сколько isValid потребуется для сбоя). Тогда и переподключение будет такое же время, так где это будет стоить дороже?

Michel Feinstein 26.03.2019 02:14

Потому что вам придется писать и поддерживать этот код (который уже существует в isValid), а затем вам придется вручную поддерживать соединение, повторно подключаться и запрашивать (и также писать этот код).

Elliott Frisch 26.03.2019 02:16

хм, имеет смысл... жаль, что никто не сделал это в виде небольшой библиотеки раньше

Michel Feinstein 26.03.2019 02:18

@ElliottFrisch Я поднимал эту проблему в HikariCP раньше здесь: github.com/brettwooldridge/HikariCP/issues/1304, и, поскольку Lambda зависает, даже пулы соединений могут не обслуживать меня.

Michel Feinstein 26.03.2019 02:20

Если ваш контейнер зависнет, ваш собственный код тоже зависнет. Вам нужно разобраться в первопричинах ваших «зависаний».

Elliott Frisch 26.03.2019 02:23

Лямбда зависает по дизайну.

Michel Feinstein 26.03.2019 02:23

Я пока пойду с isValid, может быть, протестирую, как HIkariCP ведет себя на этом.

Michel Feinstein 26.03.2019 02:24

Проверять ваше соединение каждый раз действительно излишне (особенно учитывая, что пулы соединений сделают это за вас, прежде чем арендовать соединение). Просто выполните запрос и будьте готовы к ошибкам.

Mark Rotteveel 26.03.2019 09:26

@ElliottFrisch Вы не имеют «проверить после, что вы сделали свой запрос». Это вызовет исключение или преуспеет. Нет проблем с временным окном.

user207421 26.03.2019 10:04

@MarkRotteveel да, но поскольку я буду использовать пул соединений только для проверки соединения, я мог бы просто сделать это сам и вообще не иметь пула соединений.

Michel Feinstein 26.03.2019 21:42
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
17
683
1

Ответы 1

Написание собственной оболочки вокруг java.sql.Connection, которая перехватывает ошибки и повторяет операторы после восстановления разорванного соединения, звучит заманчиво, но тогда вам также нужно будет написать свою собственную PreparedStatement и так далее, верно?

Возможно, было бы лучше сосредоточить все ваши вызовы JDBC в нескольких местах вашего приложения, т. е. написать собственную (тонкую) абстракцию для вызовов JDBC. Затем вы можете поместить свою магию повторных попыток в одно место.

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

Что вы имеете в виду под be configured to not send a query to the server? Зачем мне это? Вы говорите, что есть пулы соединений, которые при сбое соединения автоматически повторяют попытку?

Michel Feinstein 26.03.2019 21:44

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

Laurenz Albe 27.03.2019 07:53

Я хотел использовать пул соединений, но я буду запускать свой код на AWS lambda, и это немного усложняет ситуацию. AWS Lambda замораживает контейнер, когда код возвращается, и он должен вернуться через несколько секунд, иначе произойдет тайм-аут. Так что это в основном однопоточная модель. Если я установлю пул соединений, это будет пул соединений из 1 соединения, потоки управления которого будут заморожены AWS Lambda. Когда он разморозится, время будет неправильным. Вероятно, это сработает, просто выводите ошибки синхронизации при каждом новом вызове. Поэтому я подумал, что могу упростить проверку isValid самостоятельно.

Michel Feinstein 28.03.2019 12:51

Другие вопросы по теме