2014-07-24 58 views
4

昨天在Stack上有多人推薦使用try-with-resources。我現在正在爲我所有的數據庫操作執行此操作。今天,我想將語句更改爲PreparedStatement以使查詢更安全。但是,當我嘗試在資源嘗試中使用準備好的語句時,我總是收到錯誤,如'標識符預期'或';'要麼 ')'。Java在try-with-resources無法正常工作的情況下準備了語句

我在做什麼錯?或者這不可能?這是我的代碼:

try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS); 
     PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1"); 
     stmt.setInt(1, user); 
     ResultSet rs = stmt.executeQuery()) { 

     // if no record found 
     if(!rs.isBeforeFirst()) { 
      return false; 
     } 
     // if record found 
     else { 
      return true; 
     } 

    } catch (SQLException e) { 
     // log error but dont do anything, maybe later 
     String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode(); 
     return false; 

    } 
+1

在第一行,將';'改爲'){'。 (愚蠢的錯字?) – immibis

回答

1

試試這個代碼:

try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) { 
    PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1"); 

     stmt.setInt(1, user); 
     ResultSet rs = pstmt.executeQuery()) 

     // if no record found 
     if(!rs.isBeforeFirst()) { 
      return false; 
     } 
     // if record found 
     else { 
      return true; 
     } 

    } catch (SQLException e) { 
     // log error but dont do anything, maybe later 
     String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode(); 
     return false; 

    } 

注意,這裏的資源是你的連接,你必須在try塊中使用它()

+2

真的,你應該在資源創建塊內部有'PreparedStatement',以便它正確關閉。 –

+0

ok同意。另外,在這裏找到同一主題的帖子:http://stackoverflow.com/questions/8066501/how-should-i-use-try-with-resources-with-jdbc可能有人可以標記爲重複。我還沒有這個特權。 – Pat

+0

但是這篇文章並沒有涵蓋這個特定的問題。 –

1

移動

stmt.setInt(1, user); 
ResultSet rs = stmt.executeQuery() 

...內try{ /*HERE*/ }

這是因爲stmt是正在創建try (/*HERE*/) {}資源使用try{ /*HERE*/ }

嘗試 - 與資源

try (/*Create resources in here such as conn and stmt*/) 
{ 
    //Use the resources created above such as stmt 
} 

的一點是,在資源創建塊implements AutoClosable當創造了一切try塊被退出,close()被全部調用。 在您的代碼stmt.setInt(1, user);不是AutoCloseable資源,因此問題。

7

試用資源語句用於聲明(Autoclosable)資源。 Connection,PreparedStatementResultSetAutoclosable,所以這很好。

stmt.setInt(1, user)不是一種資源,而是一個簡單的聲明。在try-with-resource語句中不能有簡單的語句(沒有資源聲明)!

解決方案:創建多個試用資源語句!

try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) { 
    executeStatement(conn); 
} catch (SQLException e) { 
    // log error but dont do anything, maybe later 
    String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode(); 
    return false; 
} 

private void executeStatement(Connection con) throws SQLException { 
    try (PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id=? LIMIT 1")) { 
     stmt.setInt(1, user); 
     try (ResultSet rs = stmt.executeQuery()) { 
      // process result 
     } 
    } 
} 

(請技術上注意,把SQL語句的執行變成爲我做了一個單獨的方法不是必需的。它也可以當兩個,打開連接和創建PreparedStatement是相同的嘗試中-with-resource聲明,我認爲將連接管理與其他代碼分離是一種很好的做法)。

+1

爲什麼?你可以將'Connection'和'PreparedStatement'放在同一個資源創建塊中,然後使用'stmt' –

+2

這是正確的,但是通常在現實世界中,打開JDBC連接和執行SQL工作的應用程序應該被分開。當然,你也可以用一種方法擁有一切。 – isnot2bad

+0

夠公平的。 :) –