2012-02-13 43 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); 
    } 

此示例代码处理设置自动值。