Come dovrei usare try-with-resources con JDBC?

Ho un metodo per ottenere utenti da un database con JDBC:

public List getUser(int userId) { String sql = "SELECT id, name FROM users WHERE id = ?"; List users = new ArrayList(); try { Connection con = DriverManager.getConnection(myConnectionURL); PreparedStatement ps = con.prepareStatement(sql); ps.setInt(1, userId); ResultSet rs = ps.executeQuery(); while(rs.next()) { users.add(new User(rs.getInt("id"), rs.getString("name"))); } rs.close(); ps.close(); con.close(); } catch (SQLException e) { e.printStackTrace(); } return users; } 

Come dovrei usare Java 7 try-with-resources per migliorare questo codice?

Ho provato con il codice qui sotto, ma usa molti try , e non migliora molto la leggibilità . Dovrei usare try-with-resources in un altro modo?

 public List getUser(int userId) { String sql = "SELECT id, name FROM users WHERE id = ?"; List users = new ArrayList(); try { try (Connection con = DriverManager.getConnection(myConnectionURL); PreparedStatement ps = con.prepareStatement(sql);) { ps.setInt(1, userId); try (ResultSet rs = ps.executeQuery();) { while(rs.next()) { users.add(new User(rs.getInt("id"), rs.getString("name"))); } } } } catch (SQLException e) { e.printStackTrace(); } return users; } 

    Mi rendo conto che è stato risposto molto tempo fa, ma voglio suggerire un approccio aggiuntivo che eviti il ​​doppio blocco nidificato di try-with-resources.

     public List getUser(int userId) { try (Connection con = DriverManager.getConnection(myConnectionURL); PreparedStatement ps = createPreparedStatement(con, userId); ResultSet rs = ps.executeQuery()) { // process the resultset here, all resources will be cleaned up } catch (SQLException e) { e.printStackTrace(); } } private PreparedStatement createPreparedStatement(Connection con, int userId) throws SQLException { String sql = "SELECT id, username FROM users WHERE id = ?"; PreparedStatement ps = con.prepareStatement(sql); ps.setInt(1, userId); return ps; } 

    Non c’è bisogno di provare l’esterno nel tuo esempio, quindi puoi almeno scendere da 3 a 2, e inoltre non hai bisogno di chiudere ; alla fine dell’elenco delle risorse. Il vantaggio dell’utilizzo di due blocchi di prova è che tutto il codice è presente in primo piano, quindi non è necessario fare riferimento a un metodo separato:

     public List getUser(int userId) { String sql = "SELECT id, username FROM users WHERE id = ?"; List users = new ArrayList<>(); try (Connection con = DriverManager.getConnection(myConnectionURL); PreparedStatement ps = con.prepareStatement(sql)) { ps.setInt(1, userId); try (ResultSet rs = ps.executeQuery()) { while(rs.next()) { users.add(new User(rs.getInt("id"), rs.getString("name"))); } } } catch (SQLException e) { e.printStackTrace(); } return users; } 

    Ecco un modo conciso che utilizza lambdas e JDK 8 Supplier per adattarsi a tutto nel tentativo esterno:

      try (Connection con = DriverManager.getConnection(JDBC_URL, prop); PreparedStatement stmt = ((Supplier)() -> { try { PreparedStatement s = con.prepareStatement( "SELECT userid, name, features FROM users WHERE userid = ?"); s.setInt(1, userid); return s; } catch (SQLException e) { throw new RuntimeException(e); } }).get(); ResultSet resultSet = stmt.executeQuery()) { } 

    Che ne pensi di creare una class wrapper aggiuntiva?

     package com.naveen.research.sql; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public abstract class PreparedStatementWrapper implements AutoCloseable { protected PreparedStatement stat; public PreparedStatementWrapper(Connection con, String query, Object ... params) throws SQLException { this.stat = con.prepareStatement(query); this.prepareStatement(params); } protected abstract void prepareStatement(Object ... params) throws SQLException; public ResultSet executeQuery() throws SQLException { return this.stat.executeQuery(); } public int executeUpdate() throws SQLException { return this.stat.executeUpdate(); } @Override public void close() { try { this.stat.close(); } catch (SQLException e) { e.printStackTrace(); } } } 

    Quindi nella class chiamante puoi implementare il metodo prepareStatement come:

     try (Connection con = DriverManager.getConnection(JDBC_URL, prop); PreparedStatementWrapper stat = new PreparedStatementWrapper(con, query, new Object[] { 123L, "TEST" }) { @Override protected void prepareStatement(Object... params) throws SQLException { stat.setLong(1, Long.class.cast(params[0])); stat.setString(2, String.valueOf(params[1])); } }; ResultSet rs = stat.executeQuery();) { while (rs.next()) System.out.println(String.format("%s, %s", rs.getString(2), rs.getString(1))); } catch (SQLException e) { e.printStackTrace(); }