2012-02-13 207 views
35

如何集成創建/接收連接,查詢數據庫以及可能使用Java 7的自動資源管理處理結果的公共JDBC方法,try-with資源聲明? (TutorialJava 7自動資源管理JDBC(試用資源語句)

的Java 7之前,通常的模式是這樣的:

Connection con = null; 
PreparedStatement prep = null; 

try{ 
    con = getConnection(); 
    prep = prep.prepareStatement("Update ..."); 
    ... 
    con.commit(); 
} 
catch (SQLException e){ 
    con.rollback(); 
    throw e; 
} 
finally{ 
    if (prep != null) 
     prep.close(); 
    if (con != null) 
     con.close(); 
} 

使用Java 7,你可以去:

try(Connection con = getConnection(); PreparedStatement prep = con.prepareConnection("Update ..."){ 

    ... 
    con.commit(); 
} 

這將關閉ConnectionPreparedStatement,但是回滾呢?我無法添加包含回滾的catch子句,因爲連接僅在try塊中可用。

你還在try塊之外定義連接嗎?這裏最好的做法是什麼,特別是在使用連接池的情況下?

+1

我只是不會在這些情況下使用自動關閉。正如該術語已經表明,它只是關閉資源。順便說一句:把連接放在'try ...'塊之外是沒有用的,因爲連接已經關閉,你不能在try塊之後回滾。 – home 2012-02-13 12:06:01

+0

可能的重複http://stackoverflow.com/questions/8066501/how-should-i-use-try-with-resources-with-jdbc – Raedwald 2012-02-13 12:30:00

+2

@Rededwald:不,這不是重複。這裏是關於con.rollback()。 – Bijan 2014-06-28 07:46:24

回答

37
try(Connection con = getConnection()) { 
    try (PreparedStatement prep = con.prepareConnection("Update ...")) { 
     //prep.doSomething(); 
     //... 
     //etc 
     con.commit(); 
    } catch (SQLException e) { 
     //any other actions necessary on failure 
     con.rollback(); 
     //consider a re-throw, throwing a wrapping exception, etc 
    } 
} 

按照oracle documentation,你可以一試,與資源塊與常規try塊結合起來。 IMO,上面的例子中抓住了正確的邏輯,那就是:

  • 試圖關閉的PreparedStatement如果一切正常
  • 如果出現問題在內部塊,(不管是是)回滾當前交易
  • 無論如何關閉連接
  • 如果關閉連接出現問題,則無法回滾事務(因爲這是連接上的方法,現在處於不確定狀態),所以不要試試

在java 6及更早的版本中,我會用三重嵌套的try塊(外層try-finally,中間try-catch,內層try-finally)來做到這一點。 ARM語法確實使這個問題更加突出。

+1

您的解決方案在SQLException上回滾,但不在「RuntimeException」,「Error」(等等)上,這是一個問題。基於'finally'的代碼可以做到這一點。規則「你不能捕獲錯誤'」在出錯的情況下不會使回滾成爲可選操作。 – 2014-10-22 15:03:01

+0

@PiotrFindeisen:如果你想要的話,抓住'Throwable'而不是'SQLException'。最後不是回滾事務的正確位置,因爲無論是否出現錯誤,都會觸發finally塊。當一切正常時,你絕對不想回滾! – 2014-10-22 15:45:01

+0

是的,除非你在離開try塊之前提交(成功的情況下)。當然,在這種情況下,你有提交 - 然後回滾 - 沒有,這是不理想的,但它肯定會更好,然後在某些情況下丟失回滾。順便說一句,我建議編輯答案,因爲它是非常好的複製粘貼代碼,它應該處理所有異常。 – 2014-10-23 10:15:39

3

IMO,聲明連接和PreparedStatement外try-catch是在這種情況下可用的最佳方式。

1

如果你想使用在交易池連接,你應該以這種方式使用它:

try (Connection conn = source.getConnection()) { 
     conn.setAutoCommit(false); 
     SQLException savedException = null; 
     try { 
      // Do things with connection in transaction here... 
      conn.commit(); 
     } catch (SQLException ex) { 
      savedException = ex; 
      conn.rollback(); 
     } finally { 
      conn.setAutoCommit(true); 
      if(savedException != null) { 
       throw savedException; 
      } 
     } 
    } catch (SQLException ex1) { 
     throw new DataManagerException(ex1); 
    } 

此示例代碼處理設置自動值。