2012-03-28 5 views
0

Мне нужно изменить несколько таблиц в одной функции. Они все должны преуспеть, или все провалится. Если одна операция не удалась, я хочу, чтобы все они потерпели неудачу. У меня есть следующее:Когда нам нужно вызвать java.sql.Connection.rollback()?

public void foo() throws Exception { 
    Connection conn = null; 
    try { 
     conn = ...; 
     conn.setAutoCommit(false); 
     grok(conn); 
     conn.commit(); 
    } 
    catch (Exception ex) { 
     // do I need to call conn.rollback() here? 
    } 
    finally { 
     if (conn != null) { 
      conn.close(); 
      conn = null; 
     } 
    } 
} 

private void grok(Connection conn) throws Exception { 
    PreparedStatement stmt = null; 
    try { 
     // modify table "apple" 
     stmt = conn.prepareStatement(...); 
     stmt.executeUpdate(); 
     stmt.close(); 

     // modify table "orange" 
     stmt = conn.prepareStatement(...); 
     stmt.executeUpdate(); 
     stmt.close(); 

     ... 
    } 
    finally { 
     if (stmt != null) { 
      stmt.close(); 
     } 
    } 
} 

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

Дополнительная информация: Я использую пул соединений. В вышеприведенном примере я также должен закрыть каждое PreparedStatement, используя также окончательные утверждения, просто оставшиеся для краткости.

Спасибо

ответ

1

Вам не нужно звонить rollback(). Если соединение закрывается без завершения commit(), он будет откат.

Вам не нужно устанавливать conn в null; и поскольку блок try запускается после инициализации conn (при условии, что не может оценить значение null), вам также не нужен != null в finally.

+0

ОК обновил пример, чтобы отразить, что сопп может быть нулевым, так что даже с обновлениями я по-прежнему не нужно вызывать rollback()? Спасибо – user291701

+0

Правильно, вам не нужно вызывать откат. Ваш предыдущий пример, где 'conn' был инициализирован до того, как' try' был лучше –

+0

Это просто неправда. Вы ДОЛЖНЫ вызывать откат в соединении для ваших изменений для отката. Они не будут автоматически откатываться за вас. См. Мой ответ, но его легко проверить для себя, выбросив исключение перед вызовом commit. –

0

Если вы вызываете «commit», транзакция будет совершена. Если у вас несколько операторов вставки/обновления и одна из них не выполняется, то фиксация приведет к тому, что вставки/обновления не будут переданы в базу данных. Так что да, если вы не хотите, чтобы другие операторы фиксировали db, вам нужно вызвать откат. То, что вы в основном делаете, устанавливая autocommit в false, позволяет нескольким операторам совершать или откатываться вместе. В противном случае каждое отдельное заявление будет автоматически зафиксировано.

+0

Чтобы прояснить мой ответ, предполагается, что у вас будет несколько операторов. В вашем примере, где у вас есть только один оператор, он будет автоматически откат.Но если у вас несколько операторов, вызываемых в вашем Java-коде, вам нужно откат. – DavidB

+0

Я обновил, чтобы показать, что существует несколько операторов (ну, переменная повторно используется) - мне все еще нужен откат? Thanks – user291701

+0

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

0

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

JDBC документация https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html#call_rollback

Пример Правильное использование от док

public void updateCoffeeSales(HashMap<String, Integer> salesForWeek) 
    throws SQLException { 

    PreparedStatement updateSales = null; 
    PreparedStatement updateTotal = null; 

    String updateString = 
     "update " + dbName + ".COFFEES " + 
     "set SALES = ? where COF_NAME = ?"; 

    String updateStatement = 
     "update " + dbName + ".COFFEES " + 
     "set TOTAL = TOTAL + ? " + 
     "where COF_NAME = ?"; 

    try { 
     con.setAutoCommit(false); 
     updateSales = con.prepareStatement(updateString); 
     updateTotal = con.prepareStatement(updateStatement); 

     for (Map.Entry<String, Integer> e : salesForWeek.entrySet()) { 
      updateSales.setInt(1, e.getValue().intValue()); 
      updateSales.setString(2, e.getKey()); 
      updateSales.executeUpdate(); 
      updateTotal.setInt(1, e.getValue().intValue()); 
      updateTotal.setString(2, e.getKey()); 
      updateTotal.executeUpdate(); 
      con.commit(); 
     } 
    } catch (SQLException e) { 
     JDBCTutorialUtilities.printSQLException(e); 
     if (con != null) { 
      try { 
       System.err.print("Transaction is being rolled back"); 
       con.rollback(); 
      } catch(SQLException excep) { 
       JDBCTutorialUtilities.printSQLException(excep); 
      } 
     } 
    } finally { 
     if (updateSales != null) { 
      updateSales.close(); 
     } 
     if (updateTotal != null) { 
      updateTotal.close(); 
     } 
     con.setAutoCommit(true); 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^