Programing

JDBC와 함께 try-with-resources를 어떻게 사용해야합니까?

crosscheck 2020. 6. 25. 08:14
반응형

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-with-resources어떻게 사용해야 합니까?

아래 코드로 시도했지만 많은 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;
}

예제에서 외부 시도가 필요하지 않으므로 적어도 3에서 2로 내려갈 수 ;있으며 리소스 목록의 끝에서 닫을 필요가 없습니다 . 두 개의 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;
}

Here is a concise way using lambdas and JDK 8 Supplier to fit everything in the outer try:

    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()) {
    }

What about creating an additional wrapper class?

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();
        }
    }
}


Then in the calling class you can implement prepareStatement method as:

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();
}

참고URL : https://stackoverflow.com/questions/8066501/how-should-i-use-try-with-resources-with-jdbc

반응형