我应该如何在JDBC中使用try-with-resources?
我有一个使用JDBC从数据库中获取用户的方法:
public List<User> getUser(int userId) { String sql = "SELECT id, name FROM users WHERE id = ?"; List<User> users = new ArrayList<User>(); 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; }
我应该如何使用Java 7 试用资源来改进此代码?
我已经尝试了下面的代码,但它使用了很多try
,并没有提高可读性 。 我应该以另一种方式使用try-with-resources
吗?
public List<User> getUser(int userId) { String sql = "SELECT id, name FROM users WHERE id = ?"; List<User> 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; }
我意识到这是很久以前的答案,但要提出一个避免嵌套尝试与资源双重块的方法。
public List<User> 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; }
在你的例子中不需要外部尝试,所以你至less可以从3下降到2,也不需要closures;
在资源列表的末尾。 使用两个try块的好处是你所有的代码都在前面,所以你不必引用一个单独的方法:
public List<User> getUser(int userId) { String sql = "SELECT id, username FROM users WHERE id = ?"; List<User> 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; }
怎么样创build一个额外的包装类?
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(); } } }
然后在调用类中,您可以实现prepareStatement方法为:
(Connection con = DriverManager.getConnection(JDBC_URL,prop); PreparedStatementWrapper stat = new PreparedStatementWrapper(con,query,new Object [] {123L,“TEST”}){ @覆盖 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(); ){ 而(rs.next()) System.out.println(String.format(“%s,%s”,rs.getString(2),rs.getString(1))); catch(SQLException e){ e.printStackTrace(); }
下面是使用lambdas和JDK 8供应商的一个简洁的方法来适应外部尝试中的所有事情:
try (Connection con = DriverManager.getConnection(JDBC_URL, prop); PreparedStatement stmt = ((Supplier<PreparedStatement>)() -> { 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()) { }