2016-04-01 38 views
0

我正在減少死鎖,並指出我不應該對一個連接使用多個查詢,因爲事務可能未提交併打開,從而導致死鎖。因此,在僞代碼,是這樣的:JDBC什麼時候自動提交提交

try(Connection con = datasource.getConnection()) 
    { 
     PreparedStatement stm1 = con.prepareStatement(getSQL()); 
     stm1.setString(1, owner); 
     stm1.setTimestamp(2, Timestamp.valueOf(LocalDateTime.now())); 
     stm1.setInt(3, count); 

     int updateCount = stm1.executeUpdate(); 
     stm1.close(); 


     PreparedStatement stm2 = con.prepareStatement(getSQL2()); 
     stm2.setString(1, owner); 
     ResultSet rs = stm2.executeQuery(); 

     List<Object> results = new ArrayList<>(); 
     while(rs.next()) { 
      results.add(create(rs)); 
     } 

     return results; 
    } catch (SQLException e) { 
     throw new RuntimeException("Failed to claim message",e); 
    } 

時自動提交設置爲true什麼時候STM1提交事務?

重複使用這樣的連接還是兩個語句應該使用單獨的連接而不是好的做法?

+0

第一條語句在調用'stm1.executeUpdate();'時立即提交。 – Kayaman

+0

我會努力重新使用連接,因爲打開連接有開銷。如果你連接sql1和sql2,你也可以只做一個調用。 –

+0

Sql 1是一個更新,而2是一個選擇取決於該更新。 Sql1導致一個死鎖與不同的更新,這就是爲什麼我想知道如果sql2持有一個事務打開太久導致死鎖。無論如何,它們不能用1個查詢來表示 – pandaadb

回答

4

問題,如這些通常可以通過讀取JDBC specification回答的同時使用絕對安全。 JDBC 4.2 10.1節事務邊界和自動提交說:

當啓動一個新的事務是由 或者JDBC驅動程序或基礎數據源隱含作出的決定。儘管某些 數據源實現了明確的「開始事務」語句,但是 沒有JDBC API來執行此操作。通常,噹噹前的SQL語句需要一個並且沒有 事務已經到位時,開始一個新的事務 。 SQL:2003是否也指定給定的SQL語句 是否需要事務。

Connection屬性自動提交指定何時結束 事務。該語句完成後,啓用自動提交會導致事務在每個單獨的SQL語句後提交 。 在該聲明被認爲是「完整的」點取決於SQL語句的類型 以及什麼執行它後應用程序 :

  • 對於數據操縱語言(DML)語句,如插入,更新,刪除和DDL語句,該語句在執行完成後儘快完成 。
  • 對於Select語句,語句在關聯的結果集關閉時完成。
  • 對於CallableStatement對象或對於返回多個結果的語句,當所有關聯的 結果集已關閉且所有更新計數和輸出 參數已檢索完畢後,語句結束。

代碼中的事務被提交爲stm1.executeUpdate()部分(該交易可能已經開始準備,或執行)。在準備或執行stmt2時開始新的交易,但由於您未關閉stmt2rs,連接關閉將觸發提交。

至於是否應該重用連接和語句:取決於上下文和代碼。對於特定的工作單元,您使用單個連接。如果你想進一步重用連接,你應該使用連接池。重複使用語句只能在有意義的時候完成(否則你的代碼可能會因資源泄漏而變得複雜),並且還有連接池提供了內置語句池,從而降低了這種複雜性。

這樣的語句「[..]不應該使用一個連接使用多個查詢,因爲該事務可能未提交併打開,導致死鎖。」通常是不正確的,如果應用會導致應用程序性能不佳。它可能適用於沒有正確遵守上述自動提交規則的行爲不當行爲,或者在連接時間更長並且沒有正確完成語句的情況下(例如stmt2)。也就是說,通常情況下最好禁用自動提交併在完成後顯式提交或回滾。

您的代碼可以通過使用試穿與資源的語句和結果集也得到改善,因爲這可以確保結果集和語句都被儘快關閉,即使發生異常:

try (Connection con = datasource.getConnection()) { 
    try (PreparedStatement stm1 = con.prepareStatement(getSQL())) { 
     stm1.setString(1, owner); 
     stm1.setTimestamp(2, Timestamp.valueOf(LocalDateTime.now())); 
     stm1.setInt(3, count); 

     int updateCount = stm1.executeUpdate(); 
    } 

    try (PreparedStatement stm2 = con.prepareStatement(getSQL2())) { 
     stm2.setString(1, owner); 
     try (ResultSet rs = stm2.executeQuery()) { 

      List<Object> results = new ArrayList<>(); 
      while(rs.next()) { 
       results.add(create(rs)); 
      } 
      return results; 
     } 
    } 
} catch (SQLException e) { 
    throw new RuntimeException("Failed to claim message", e); 
} 
1

當禁用自動提交模式時,只有在顯式調用方法提交之前,纔會提交SQL語句。之前調用方法提交後執行的所有語句都包含在當前事務中並作爲一個單元一起提交。

當您設置自動提交true時,它立即提交到數據庫中。

它很好的做法,重新使用connection.This是,只要在同一個連接沒有被兩個線程在