JdbcTemplate 사용 및 람다식으로 축약하기

2022. 1. 17. 19:49북리뷰/토비의 봄

728x90

이전 포스팅에서 템플릿과 콜백의 기본적인 원리와 동작방식, 만드는 방법에 대해 알아보았다. 스프링에도 JDBC를 이용하는 DAO에서 사용할 수 있도록 다양한 템플릿과 콜백을 제공한다.

스프링에서 제공하는 JDBC 코드용 기본 템플릿은 JdbcTemplate이다. 한번 사용해보자

public class UserDao {
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    ...
}

update()

update() 메서드는 PreparedStatementCreator타입을 콜백 받아서 사용한다. 다음과 같이 사용하면 된다

public class UserDao {
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public void add(User user) {
        this.jdbcTemplate.update("insert into users(id, name, password) values (?,?,?)",
                user.getId(), user.getName(), user.getPassword());
    }

    public void deleteAll() {
        this.jdbcTemplate.update("delete from users");
    }
    ...
}

queryForObject()

만약 select문 같이 결과 값을 가져와야 하는 SQL쿼리는 어떻게 처리할까? queryForObject() 메서드를 사용하면 된다. 이 메서드는 ResultSet을 전달받는 RowMapper을 콜백으로 전달받는다.

public class UserDao {
    public User get(String id) {
        return this.jdbcTemplate.queryForObject("select * from users where id = ?",
                new Object[]{id}, 
                new RowMapper<User>() {
                    @Override
                    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                        User user = new User();
                        user.setId(rs.getString("id"));
                        user.setName(rs.getString("name"));
                        user.setPassword(rs.getString("password"));
                        return user;
                    }
                });
    }

    public int getCount() {
        return this.jdbcTemplate.queryForObject("select count(*) from users", Integer.class);
    }
    ...
}

query()

RowMapper을 좀 더 사용해보자. 현재 등록되어 있는 모든 사용자 정보를 리스트 형태로 가져오는 getAll() 메서드를 추가해보자. 메서드를 제작하기 전에 테스트코드를 우선 제작해보자.

    @Test
    public void getAll() {
        dao.deleteAll();

        List<User> users0 = dao.getAll();
        assertThat(users0.size(), is(0));

        dao.add(user1);
        List<User> users1 = dao.getAll();
        assertThat(users1.size(), is(1));
        checkSameUser(user1, users1.get(0));

        dao.add(user2);
        List<User> users2 = dao.getAll();
        assertThat(users2.size(), is(2));
        checkSameUser(user1, users2.get(0));
        checkSameUser(user2, users2.get(1));

        dao.add(user3);
        List<User> users3 = dao.getAll();
        assertThat(users3.size(), is(3));
        checkSameUser(user1, users3.get(0));
        checkSameUser(user2, users3.get(1));
        checkSameUser(user3, users3.get(2));
    }

이제 테스트를 성공시키는 getAll() 메서드를 제작해보자

public class UserDao {
    public List<User> getAll() {
        return this.jdbcTemplate.query("select * from users order by id",
                new RowMapper<User>() {
                    @Override
                    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                        User user = new User();
                        user.setId(rs.getString("id"));
                        user.setName(rs.getString("name"));
                        user.setPassword(rs.getString("password"));
                        return user;
                    }
                });
    }
    ...
}

중복 제거

get()과 getAll()을 보면 겹치는 부분이 있다.

 new RowMapper<User>() {
                    @Override
                    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                        User user = new User();
                        user.setId(rs.getString("id"));
                        user.setName(rs.getString("name"));
                        user.setPassword(rs.getString("password"));
                        return user;
                    }
                }

바로 이 부분이다. 이 부분을 따로 변수로 빼서 사용하도록 하자.

public class UserDao {
    private JdbcTemplate jdbcTemplate;
    private RowMapper<User> userRowMapper =
            new RowMapper<User>() {
                    @Override
                    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                        User user = new User();
                        user.setId(rs.getString("id"));
                        user.setName(rs.getString("name"));
                        user.setPassword(rs.getString("password"));
                        return user;
                    }
                };


    public void setJdbcTemplate(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public User get(String id) {
        return this.jdbcTemplate.queryForObject("select * from users where id = ?",
                new Object[]{id}, this.userRowMapper);
    }

    public List<User> getAll() {
        return this.jdbcTemplate.query("select * from users order by id", this.userRowMapper);
    }

    ...
}

람다식 활용

위 코드들을 람다식을 활용하면 코드를 더 간소화 시킬 수 있다.

public class UserDao {
    private JdbcTemplate jdbcTemplate;
    private RowMapper<User> userRowMapper =
            (rs, rowNum) -> new User(rs.getString("id"),
                    rs.getString("name"),
                    rs.getString("password"));


    public void setJdbcTemplate(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public void add(User user) {
        this.jdbcTemplate.update("insert into users(id, name, password) values (?,?,?)",
                user.getId(), user.getName(), user.getPassword());
    }

    public User get(String id) {
        return this.jdbcTemplate.queryForObject("select * from users where id = ?",
                new Object[]{id}, this.userRowMapper);
    }

    public void deleteAll() {
        this.jdbcTemplate.update("delete from users");
    }

    public int getCount() {
        return this.jdbcTemplate.queryForObject("select count(*) from users", Integer.class);
    }

    public List<User> getAll() {
        return this.jdbcTemplate.query("select * from users order by id", this.userRowMapper);
    }
}
728x90