Требуется откат, если java.sql.Connection # commit() выдает исключение?

Согласно документация JAVA, Connection#commit() может бросить SQLException. Мой вопрос заключается в том, следует ли еще откатить откат в этом сценарии.

Например:

Connection con = null;
try {
    // assume this method returns an opened connection with setAutoCommit(false)
    con = createConnection(); 

    // do DB stuff

    con.commit();
} catch (SQLException e) {
    if (con != null) {
        // what if con.commit() failed, is this still necessary,
        // will it hurt anything?
        con.rollback();
    }
} finally {
    if (con != null) {
        con.close();
    }
}

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

Ответы

Ответ 1

Я бы сделал явный откат только для целей очистки. Хотя изменения не будут сохраняться в db в любом случае, кажется, что явным образом позволяю базе данных знать, что вы здесь сделали. Точно так же, как вы закрываете соединение явно, не дожидаясь, когда объект Connection будет собран с помощью мусора.

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

Ответ 2

Откат важен, даже если commit завершился неудачно, согласно Java 1.6 JDBC docs:

Настоятельно рекомендуется, чтобы приложение явно фиксировало или возвращает активную транзакцию до вызова метода close. Если вызывается метод close, и есть активная транзакция, результаты определяются по реализации.

Это означает, что если вы явно не вызываете откат, некоторые реализации JDBC могут вызывать фиксацию перед закрытием соединения.

Еще одна веская причина отката - это предложение Xepoch, и при использовании пула соединений это еще более важно. Когда вы получаете соединение из пула соединений, большинство реализаций выполнит connection.setAutoCommit(defaultAutoCommit) перед тем, как дать вам соединение и в соответствии с JavaDocs:

Если этот метод вызывается во время транзакции и режима автоматической фиксации, транзакция совершена

Если connection.rollback() выдает исключение - тогда это сложно...

Ответ 3

"Возвращает открытое соединение?" Если это соединение используется в пуле (и может быть в будущем), вы не хотите, чтобы другая транзакция выполняла вашу более раннюю работу. Я видел МНОГО случаев клиента/решения о подключении пула подключенных драйверов, которые соответствуют интерфейсам JDBC, и Connection.close() также можно использовать, чтобы просто вернуть соединение обратно в пул.

Кроме того, лучше try{}catch{} ваш rollback() (отредактируйте, просто прочитайте весь свой пост, но мне всегда нравится регистрировать исключение при откате)

Ответ 4

Обычно я делаю это:

boolean bSuccess = false;
Connection con = null;
try {
    // assume this method returns an opened connection with setAutoCommit(false)
    con = createConnection(); 

    // do DB stuff

    bSuccess = true;
} catch (SQLException e) 
{
}
finally 
{
    try
    {
       if (con != null) 
       {
          if(bSuccess)
             con.commit()
          else
             con.rollback();

          con.close();
       }
    }
    catch(SQLException sqle)
    {
      log("Log the error here");
      // do nothing we tried
    }
}

Говоря об этом, я никогда не видел, чтобы комманда или откат не выполнялись, если запросы выполнялись.
Если у вас есть ожидающие транзакции, большинство баз данных имеют инструменты для их освобождения. Большинство серверов приложений будут продолжать повторять транзакции и откаты, пока они не смогут подключиться.

Возможно, вам захочется посмотреть сообщение: Нужно ли писать ROLLBACK, если запросы не выполняются?