#java #jdbc
Вопрос:
В документации Java по интерфейсу java.sql.Connection говорится следующее о методе close (): «Настоятельно рекомендуется, чтобы приложение явно фиксировало или откатывало активную транзакцию перед вызовом метода close. Если вызывается метод закрытия и имеется активная транзакция, результаты определяются реализацией.»
Это создает тонкую, но серьезную проблему: если я вызываю метод отката() Соединения, но этот метод завершается неудачно (например, происходит тайм-аут), то могу ли я вызвать метод close() этого соединения? Возможно ли, что при вызове метода close() все еще существует активная транзакция, и поэтому результаты определяются реализацией, и поэтому транзакция может быть зафиксирована?
Я могу отказаться от вызова метода close() в случае сбоя функции rollback (), но это может привести к тому, что ресурсы JDBC не будут освобождены. Кроме того, возможно, в конечном итоге будет вызван метод close () (возможно, когда объект подключения будет собран как мусор). Если это так, то такой подход не поможет.
Итак, что я должен делать, когда метод rollback() для соединения завершается сбоем? Если метод rollback() завершится неудачно, могу ли я по-прежнему вызывать метод close() этого соединения?
Комментарии:
1. В общем случае, если откат не удался, вы либо сделали что-то неправильно (например, вызвали фиксацию в автоматической фиксации, или когда вы находитесь в распределенной транзакции, или соединение закрыто), либо что-то настолько нарушено (например, проблемы с подключением или несоответствие состояния между драйвером и сервером), что закрытие соединения, вероятно, является единственным разумным действием, оставшимся. В такой ситуации вполне вероятно, что сервер базы данных выполнит откат после закрытия соединения.
Ответ №1:
Если я вызываю
rollback()
метод aConnection
, но этот метод завершается неудачно (например, происходит тайм-аут), то могу ли я вызватьclose()
метод thisConnection
?
Согласно спецификации 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 кажется плохим. Не имеет смысла разрешать драйверу совершать транзакцию, когда транзакция активна и вызывается метод закрытия объекта подключения. В таком случае транзакция всегда должна быть отменена (откатана).