Jdbc Template으로 쉽게 DB 활용하기
Table of contents
Jdbc Template 란?
스프링은 JDBC를 위한 다양한 메서드를 제공하고 있으며, JdbcTemplate 클래스를 생성하면 된다.
파라미터로는 DataSource 를 입력해주면 된다.
Jdbc Template 사용
@Configuration
public class UserDaoConfig {
    @Bean
    public UserDao userDao() {
        return new UserDao(dataSource());
    }
    @Bean
    public DataSource dataSource() {
        Map<String, String> env = System.getenv();
        SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
        dataSource.setDriverClass(com.mysql.cj.jdbc.Driver.class);
        dataSource.setUrl(env.get("DB_HOST"));
        dataSource.setUsername(env.get("DB_USER"));
        dataSource.setPassword(env.get("DB_PASSWORD"));
        return dataSource;
    }
}
위와 같은, DataSource 객체를 Configuration 에너테이션이 있는 소스파일안에서 스프링 빈 저장소에 의해 입력받게 될 것이다.
JdbcTemplate 를 사용하고 싶은 파일에서는,
public class UserDao {
    private final JdbcTemplate jdbcTemplate;
    
    public UserDao(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
}
DI 주입에 의해 입력된 dataSource 는 기본 생성자에서 JdbcTemplate 의 매개변수로 입력되고, JdbcTemplate 객체가 초기화 되어, 다양한 메서드를 사용할 수 있다.
jdbcTemplate.update()
public class UserDao {
	public void insert(final User user) throws ClassNotFoundException, SQLException {
    	    jdbcTemplate.update("INSERT INTO users(id,name,password) values(?,?,?)", 
        	                    user.getId(), user.getName(), user.getPassword());
    	}
	 public void deleteAll() throws SQLException, ClassNotFoundException {
    	    jdbcTemplate.update("delete from users");
    	}
}
jdbcTemplate 를 사용했더니, 엄청나게 간결해졌다.
jdbcTemplate.update 메서드는, 위와 같이 ResultSet 이 없는, MYSQL 에 쿼리문만 전달 시켜서 실행시키는 구문을 실행시킬 때 사용하면 된다.
update("SQL 쿼리문", 쿼리문에 바인딩 할 시 파라미터 )
jdbcTemplate.queryForObject()
public class UserDao {
    
    RowMapper<User> rowMapper = new RowMapper<User>() {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User(rs.getString("id"), rs.getString("name"), rs.getString("password"));
            return user;
        }
    };
    
	public int getCount() throws SQLException, ClassNotFoundException {
        String sql = "SELECT COUNT(*) AS COUNT FROM USERS";
        return this.jdbcTemplate.queryForObject(sql, Integer.class);
    }
    public User getById(String id) throws SQLException, ClassNotFoundException {
        String sql = "SELECT * FROM USERS WHERE ID = ?";
        return this.jdbcTemplate.queryForObject(sql, rowMapper, id);
    }
}
queryForObject 는 SQL 쿼리문 실행 결과로 부터 원하는 데이터를 추출할 수 있다.
기본 사용 방법은 queryForObject(SQL 구문, 반환타입, 바인딩 할 시 파라미터) 이다.
예를 들면, jdbcTemplate.queryForObject("SELECT password FROM USERS WHERE id = ?",String.class,"1234") 라고 하면, id가 “1234” 인 유저의 패스워드를 String 타입으로 반환받겠다는 의미이다.
따라서, getCount() 메서드에서는 queryForObject(sql,Integer.class) 로 사용하였고, 이는 quertForInt(sql) 로 사용할 수 도 있다.
getById() 메서드에서는 SQL 결과물 정보를 USER 객체에 인스턴스 변수에 각각 저장한 뒤, 객체를 반환하기 위해서 rowMapper 라는 것을 사용하였다.
RowMapper 는 SQL 결과물 테이블에서 행 하나를 맵핑한다고 생각하면 된다. RowMapper 는 인터페이스이기 때문에, @Override 에너테이션이 있는 mapRow() 메서드를 원하는 방식으로 오버라이딩 해주어야 한다. 쿼리문의 결과로 생성되는 ResultSet 객체에서 getString("속성명") 을 통해서 User 객체의 인스턴스에 데이터를 저장한 후 User 를 반환하게 구현하면 된다.
jdbcTemplate.query()
query() 메서드는 ResultSet 의 모든 로우를 열람하면서, 로우마다 rowMapper 로 구현한 mapRow 메서드를 사용한다. 따라서, DB에서 가져오는 로우의 개수만큼 호출될 것이다. 그리고, 이러한 결과를 List 객체에 담아서 반환해준다.
public class UserDao {
    
    RowMapper<User> rowMapper = new RowMapper<User>() {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User(rs.getString("id"), rs.getString("name"), rs.getString("password"));
            return user;
        }
    };    
    
	public List<User> getAll(){
        String sql = "SELECT * FROM USERS ORDER BY id";
        return this.jdbcTemplate.query(sql, rowMapper);
    }
}
위와 같은 코드를 실행시키면, 쿼리문 실행 결과를 바탕으로 한 데이터를 User 객체에 담은 뒤, 그 User 객체들을 담고 있는 List 객체가 반환되어 .size() 나 .get() 과 같은 List 메서드를 활용하여 데이터를 다룰 수 있게 된다.