В JDBC, что мне делать, если соединение не удается откатить?

#java #jdbc

Вопрос:

В документации Java по интерфейсу java.sql.Connection говорится следующее о методе close (): «Настоятельно рекомендуется, чтобы приложение явно фиксировало или откатывало активную транзакцию перед вызовом метода close. Если вызывается метод закрытия и имеется активная транзакция, результаты определяются реализацией.»

Это создает тонкую, но серьезную проблему: если я вызываю метод отката() Соединения, но этот метод завершается неудачно (например, происходит тайм-аут), то могу ли я вызвать метод close() этого соединения? Возможно ли, что при вызове метода close() все еще существует активная транзакция, и поэтому результаты определяются реализацией, и поэтому транзакция может быть зафиксирована?

Я могу отказаться от вызова метода close() в случае сбоя функции rollback (), но это может привести к тому, что ресурсы JDBC не будут освобождены. Кроме того, возможно, в конечном итоге будет вызван метод close () (возможно, когда объект подключения будет собран как мусор). Если это так, то такой подход не поможет.

Итак, что я должен делать, когда метод rollback() для соединения завершается сбоем? Если метод rollback() завершится неудачно, могу ли я по-прежнему вызывать метод close() этого соединения?

Комментарии:

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

Ответ №1:

Если я вызываю rollback() метод a Connection , но этот метод завершается неудачно (например, происходит тайм-аут), то могу ли я вызвать close() метод this Connection ?

Согласно спецификации JDBC, SQLTransactionRollbackException является переходным SQLException .

Переходный SQLException процесс будет возникать в ситуациях, когда ранее неудачная операция может завершиться успешно, когда операция повторяется без какого-либо вмешательства функций уровня приложения. После SQLException того, как SQLTransientConnectionException произойдет переходный процесс, отличный от этого, приложение может предположить, что соединение все еще действует.

Таким образом, если rollback() сбой произошел с an SQLTransactionRollbackException , вы должны иметь возможность close() подключиться или повторить rollback() попытку . (Если бы вы позвонили close() , то после звонка rollback() водителю было бы неправильно совершать транзакцию.)

Однако в случае rollback() сбоя с a SQLTransientConnectionException соединение будет недействительным. Звонок close() может не сработать … или он может зафиксировать транзакцию 1. Осторожный подход состоит в том , чтобы просто отказаться от Connection и верить, что база данных автоматически откатит транзакцию. В качестве альтернативы, если вы можете выяснить (из документации вашего водителя и т. Д.), Что a close() не будет совершать транзакцию, Затем позвоните close() .

В последнем случае, я думаю, мы должны предположить, что, когда драйвер JDBC обнаружит, что соединение было потеряно, он освободит Socket и другие ресурсы, насколько это возможно. Пользователь Socket , чье сетевое соединение было разорвано, не может быть «повторно открыт», поэтому нет смысла цепляться за него.

Если мы не позвонили close() и просто забыли об Connection этом (после сбоя отката), утечка ресурсов, вероятно, не имеет значения, так как:

  • сбои подключения к базе данных должны быть редким явлением,
  • GC Java должен в конечном итоге завершить Connection и выпустить соответствующие Socket и т. Д.

1 — В теории. В JDBC Javadoc говорится, что не указано, что произойдет, если вы close() подключитесь к активной транзакции. Но было бы полезно проверить документацию для конкретных драйверов, которые вы используете.

Комментарии:

1. Итак, лучший способ-оставить соединение (не вызывать его метод close ()), если откат завершится неудачно, не так ли? Но, если я не вызову close() Соединения, будет ли этот метод вызван позже, когда этот объект соединения будет собран в мусор?

2. Если вы не знаете , что конкретный драйвер, который вы используете, будет спонтанно совершать транзакции close() , то самое безопасное -разорвать соединение. Это будет мусор, собранный в какое-то время в будущем. Ты не знаешь, когда.

3. @StephenC Просто полагаться на GC не обязательно помогает. Водитель может попытаться выполнить чистое закрытие в финализаторе и, таким образом, все равно попытаться совершить в этом случае. Тем не менее, я думаю, что ваш совет просто потерять соединение не является хорошей идеей: соединения JDBC следует открывать с помощью try-with-resources, чтобы избежать утечки ресурсов. Следование этому совету значительно повышает вероятность утечки ресурсов в приложениях.

4. Хммм … возможно, вам нужно провести некоторое исследование того, что делают настоящие драйверы JDBC, в отличие от того, что говорится в спецификации, они могут делать.

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