BackEnd/JDBC

[JDBC] DAO 리팩토링 3 - DbTemplate 리팩토링

샤아이인 2022. 3. 13.

이전글을 기반으로 하는 리팩토링 기록 입니다.

 

[JDBC] DAO 리팩토링 2 - 하나의 Template 으로 이동

다음과 같이 하나의 Template 안에 기존의 코드들을 전부 모아두었다. 기존 코드는 직전 글에서 설명했었다. [JDBC] DAO 리팩토링 1 - 개별 Template 만들기 이전 글의 코드를 리팩토링 한 과정입니다. 변

blogshine.tistory.com

 

1. DbTemplate 리팩토링 하기

기존 DbTemplate이 update 메서드는 다음과 같다.

public Long executeUpdate(String sql, PreparedStatementSetter pss) {
    Connection connection = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        connection = getConnection();
        pstmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        pss.setParameters(pstmt);
        pstmt.executeUpdate();

        rs = pstmt.getGeneratedKeys();
        if (rs.next()) {
            return rs.getLong(1);
        }
    } catch (SQLException e) {
        return -1L;
    } finally {
        DbCleaner.close(connection, pstmt, rs, dataSource);
    }
    return -1L;
}

이 메서드를 호출할때 인자로 PreparedStatementSetter를 호출하고 있는데, 이를 사용하려면 외부에서 다음과 같이 넘겨주어야 한다.

PreparedStatementSetter pss = new PreparedStatementSetter() {
    @Override
    public void setParameters(PreparedStatement pstmt) throws SQLException {
        pstmt.setString(1, user.getUserId());
        pstmt.setString(2, user.getPassword());
        pstmt.setString(3, user.getName());
        pstmt.setString(4, user.getEmail());
    }
};

 

위와 같은 함수를 executeUpdate(sql, pss)의 메서드로 전달하는 것 인다. (더 리팩토링 하면 람다식을 사용할 수 있을것 같다)

하지만 위와 같은 과정을 불편하다. 항상 setParameters의 메서드를 오버라이딩 하여 넘겨줘야 할까?

그냥 인자를 넘기면 되게할수 없을까?

 

다음과 같이 리팩토링 할 수 있다.

public Long executeUpdate(String sql, PreparedStatementSetter pss) {
    Connection connection = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        connection = getConnection();
        pstmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        pss.setParameters(pstmt);
        pstmt.executeUpdate();

        rs = pstmt.getGeneratedKeys();
        if (rs.next()) {
            return rs.getLong(1);
        }
    } catch (SQLException e) {
        return -1L;
    } finally {
        DbCleaner.close(connection, pstmt, rs, dataSource);
    }
    return -1L;
}
// 새롭게 추가된 부분!!!!!!!!
public Long executeUpdate(String sql, Object... parameters) {
    return executeUpdate(sql, getPreparedStatementSetter(parameters));
}

private PreparedStatementSetter getPreparedStatementSetter(Object[] parameters) {
    return new PreparedStatementSetter() {
        @Override
        public void setParameters(PreparedStatement pstmt) throws SQLException {
            for (int i = 0; i < parameters.length; i++) {
                pstmt.setObject(i + 1, parameters[i]);
            }
        }
    };
}

우선 새롭게 추가한 executeUpdate는 인자로 Object... 을 받는다. 잘 보면 가변인자 문법을 사용하고 있다.

즉 지정할 파라미터들을 가변적으로 받게 된다.

이렇게 받은 파라미터들을 getPreparedStatementSetter를 통해 pss로 변환하여 기존의 executeUpdate(sql, pss)의 인자로 전달하면 된다.

 

따라서 사용하는 입장에서는 다음과 같이 사용할 수 있다.

public Long save(User user) {
    DbTemplate template = new DbTemplate(dataSource);
    String SQL = "INSERT INTO user_info (user_id, password, name, email) VALUES (?, ?, ?, ?)";
    Long saveId = template.executeUpdate(SQL, user.getUserId(), user.getPassword(), user.getName(), user.getEmail());
    user.setId(saveId);
    return saveId;
}

executeUpdate 에게 인자를 전달하게 변경 하였다!!

 

이런식으로 나머지 메서드 들도 리팩토링 진행하였습니다.

 

2. 전체 코드

- DbTemplate

public class DbTemplate {
    private final DataSource dataSource;

    public DbTemplate(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    private Connection getConnection() {
        return DataSourceUtils.getConnection(dataSource);
    }

    public Long executeUpdate(String sql, PreparedStatementSetter pss) {
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            connection = getConnection();
            pstmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            pss.setParameters(pstmt);
            pstmt.executeUpdate();

            rs = pstmt.getGeneratedKeys();
            if (rs.next()) {
                return rs.getLong(1);
            }
        } catch (SQLException e) {
            return -1L;
        } finally {
            DbCleaner.close(connection, pstmt, rs, dataSource);
        }
        return -1L;
    }

    public Long executeUpdate(String sql, Object... parameters) {
        return executeUpdate(sql, getPreparedStatementSetter(parameters));
    }

    public <T> T executeQuery(String sql, RowMapper<T> mapper, PreparedStatementSetter pss) {
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            connection = getConnection();
            pstmt = connection.prepareStatement(sql);
            pss.setParameters(pstmt);
            rs = pstmt.executeQuery();

            T value = mapper.rowMapper(rs);
            if (value != null) return value;
        } catch (SQLException e) {
            return null;
        } finally {
            DbCleaner.close(connection, pstmt, rs, dataSource);
        }
        return null;
    }

    public <T> T executeQuery(String sql, RowMapper<T> mapper, Object... parameters) {
        return executeQuery(sql, mapper, getPreparedStatementSetter(parameters));
    }

    private PreparedStatementSetter getPreparedStatementSetter(Object[] parameters) {
        return new PreparedStatementSetter() {
            @Override
            public void setParameters(PreparedStatement pstmt) throws SQLException {
                for (int i = 0; i < parameters.length; i++) {
                    pstmt.setObject(i + 1, parameters[i]);
                }
            }
        };
    }

    public <T> List<T> list(String sql, RowMapper<T> mapper, PreparedStatementSetter pss) {
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        List<T> list = new ArrayList<>();

        try {
            connection = getConnection();
            pstmt = connection.prepareStatement(sql);
            pss.setParameters(pstmt);
            rs = pstmt.executeQuery();

            while (rs.next()) {
                list.add(mapper.rowMapper(rs));
            }

            return list;
        } catch (SQLException e) {
            return null;
        } finally {
            DbCleaner.close(connection, pstmt, rs, dataSource);
        }
    }

    public <T> List<T> list(String sql, RowMapper<T> mapper, Object... parameters) {
        return list(sql, mapper, getPreparedStatementSetter(parameters));
    }
}

 

 

- DbUserRepository

@Primary
@Repository
public class DbUserRepository implements UserRepository {
    private final DataSource dataSource;

    public DbUserRepository(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Long save(User user) {
        DbTemplate template = new DbTemplate(dataSource);
        String SQL = "INSERT INTO user_info (user_id, password, name, email) VALUES (?, ?, ?, ?)";
        Long saveId = template.executeUpdate(SQL, user.getUserId(), user.getPassword(), user.getName(), user.getEmail());
        user.setId(saveId);
        return saveId;
    }

    @Override
    public Optional<User> findByUserId(String userId) {
        RowMapper<User> mapper = new RowMapper<User>() {
            @Override
            public User rowMapper(ResultSet rs) throws SQLException {
                while (rs.next()) {
                    User user = new User(rs.getString("user_id"), rs.getString("password"), rs.getString("name"), rs.getString("email"));
                    user.setId(rs.getLong("id"));
                    return user;
                }
                return null;
            }
        };

        DbTemplate template = new DbTemplate(dataSource);

        String SQL = "SELECT id, user_id, password, name, email FROM user_info WHERE user_id = (?)";
        return Optional.ofNullable(template.executeQuery(SQL, mapper, userId));
    }

    @Override
    public List<User> findAll() {
        RowMapper<User> mapper = new RowMapper<User>() {
            @Override
            public User rowMapper(ResultSet rs) throws SQLException {
                User user = new User(rs.getString("user_id"), rs.getString("password"), rs.getString("name"), rs.getString("email"));
                user.setId(rs.getLong("id"));
                return user;
            }
        };

        DbTemplate template = new DbTemplate(dataSource);

        String SQL = "SELECT id, user_id, password, name, email FROM user_info";
        return template.list(SQL, mapper);
    }

    @Override
    public boolean delete(String userId) {
        DbTemplate template = new DbTemplate(dataSource);

        String SQL = "DELETE FROM user_info WHERE user_id = (?)";
        Long resultId = template.executeUpdate(SQL, userId);

        if (resultId != -1) {
            return true;
        }
        return false;
    }

    @Override
    public boolean update(String userId, User updateParam) {
        DbTemplate template = new DbTemplate(dataSource);

        String SQL = "UPDATE user_info SET user_id = (?), password = (?), name = (?), email = (?) WHERE user_id = (?)";
        Long resultId = template.executeUpdate(SQL, updateParam.getUserId(), updateParam.getPassword(), updateParam.getName(), updateParam.getEmail(), updateParam.getUserId());

        if (resultId != -1) {
            return true;
        }
        return false;
    }
}

 

댓글