1. JDBC Template이란?
JDBC Template은 개발자가 JDBC 기술을 쉽게 사용할 수 있도록 도와주는 클래스로 아래와 같은 작업을 대신 처리한다.
- Connection 획득
- statement 생성 및 실행
- Connection, statement, resultset 종료
- SQL 조회, 업데이트, ResultSet 반복호출 등
- JDBC 예외 발생시 org.springframework.dao 패키지에 정의된 일반 예외로 변환
위와 같은 기능들을 대신 해주기 때문에 이전에 작성한 JDBC 코드들은 훨씬 간편해진다. JDBC Template은 아래와 같이 선언한다.
@Repository
public class RoleDao {
private JdbcTemplate jdbcTemplate;
@Autowired
public RoleDao(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
...
}
위와 같이 Dao 클래스에는 일반적으로 @Repository를 붙여 Component Scan시 Bean으로 등록하도록 해준다. 클래스 안을 살펴보면 생성자에서 dataSource를 받아 JdbcTemplate 객체 생성 시 넘겨준다. 이와 같이 기본 생성자 없이 인자를 전달받는 생성자만 있다면 Spring은 Bean에 등록된 해당 자료형 객체를 찾아 넣어준다. 즉, dataSource 객체는 Bean으로 등록된 상태여야 한다.
2. queryForObject() 메서드
queryForObject() 메서드는 기본적으로 단건을 조회할 때 사용하는 메서드다. 즉, 아래와 같이 결과 쿼리라인이 1개일 때 사용한다.
// RoleDaoSqls.java (sql문을 모아놓은 java 클래스 파일)
public static final String SELECT_ID = "SELECT role_id FROM role where description=?";
// RoleDao.java
public List<Integer> selectId(String description){
return this.jdbcTemplate.queryForList(SELECT_ID, Integer.class, description);
}
// main문
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
RoleDao roleDao = ac.getBean(RoleDao.class);
Integer roleId = roleDao.selectId("Developer");
// Integer list = roleDao.selectId("CEO"); -> Incorrect result size: expected 1, actual 2 에러
System.out.println(roleId);
- queryForObject(쿼리문, 반환할 클래스, ?에 전달할 인자): 단건 조회
이와 같이 queryForObject 메서드는 단 한 개의 결과만 가져올 수 있기 때문에 아래에 주석 처리된 문장은 에러가 발생한다. (CEO에 해당하는 결과는 2개 쿼리라인이 발생한다.) 만약 Integer 같은 기존에 선언된 타입이 아니라 우리가 선언한 클래스 타입으로 반환받고 싶다면 RowMapper를 사용할 수 있다. 이를 위해서 우리는 두 가지 방법을 사용할 수 있다. 첫 번째 방법은 아래와 같다.
// RoleDaoSqls.java
public static final String SELECT_ONE_ROW = "SELECT role_id, description FROM role WHERE role_id=?";
// RoleMapper.java
public class RoleMapper implements RowMapper<Role> {
@Override
public Role mapRow(ResultSet rs, int rowNum) throws SQLException{
Role role = new Role();
role.setRoleId(rs.getInt("role_id"));
role.setDescription(rs.getString("description"));
return role;
}
}
// RoleDao.java
public Role selectOneRow1(int roleId){
return this.jdbcTemplate.queryForObject(SELECT_ONE_ROW, new RoleMapper(), roleId);
}
// main문
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
RoleDao roleDao = ac.getBean(RoleDao.class);
Role role = roleDao.selectOneRow1(100);
System.out.println(role);
}
위와 같이 RowMapper 인터페이스를 기반으로 클래스를 만들고 해당 클래스에서 mapRow 메서드를 작성해주면 된다. 이때 mapRow 메서드의 rs는 ResultSet 객체, rowNum은 결과로 받은 sql 행의 개수라고 생각하면 된다. 그리고 만든 클래스의 객체를 생성하여 위와 같이 queryForObject로 넘겨주면 Role 객체를 얻어올 수 있다. 위와 같이 클래스를 만들지 않고 필드로 선언하여 사용할 수도 있다.
// RoleDao.java
private RowMapper<Role> roleMapper = new RowMapper<Role>() {
@Override
public Role mapRow(ResultSet rs, int rowNum) throws SQLException{
Role role = new Role();
role.setRoleId(rs.getInt("role_id"));
role.setDescription(rs.getString("description"));
return role;
}
};
public Role selectOneRow1(int roleId){
return this.jdbcTemplate.queryForObject(SELECT_ONE_ROW, roleMapper, roleId);
}
혹은 아래와 같이 queryForObject를 사용할 때 선언하는 방식도 사용할 수 있다.
// RoleDao.java
public Role selectOneRow2(int roleId){
return this.jdbcTemplate.queryForObject(SELECT_ONE_ROW,
(rs, rowNum) -> new Role(
rs.getInt("role_id"),
rs.getString("description")
),
roleId);
}
// main문
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
RoleDao roleDao = ac.getBean(RoleDao.class);
Role role = roleDao.selectOneRow2(100);
System.out.println(role);
}
3. query() 메서드
query 메서드를 사용하면 queryForObject와 다르게 여러 건의 결과를 받아올 수 있다. 이때 "여러 건"의 결과를 받아오므로 해당 메서드의 결과는 List 자료형에 담아진다. 즉, 아래와 같이 사용할 수 있다.
// RoleDaoSqls.java
public static final String SELECT_ALL = "SELECT role_id, description FROM role order by role_id";
// RoleDao.java
public List<Role> selectAll(){
return this.jdbcTemplate.query(SELECT_ALL,
(rs, rowNum) -> new Role(
rs.getInt("role_id"),
rs.getString("description")));
}
// main문
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
RoleDao roleDao = ac.getBean(RoleDao.class);
List<Role> roles = roleDao.selectAll();
for(Role role: roles) {
System.out.println(role);
}
}
'BackEnd > Spring' 카테고리의 다른 글
[Spring JDBC] NamedParameterJdbcTemplate (0) | 2023.01.28 |
---|---|
[Spring JDBC] Jdbc Template이란? (Insert, Update, Delete) (0) | 2023.01.28 |
[Spring JDBC] DataSource를 통해 데이터베이스 연결하기 (0) | 2023.01.27 |
[Spring JDBC] Connection Pool, DataSource란? (0) | 2023.01.27 |
[Spring] Java Config를 활용한 Bean 등록 방법 (0) | 2023.01.25 |