1. JdbcTemplate이란?
기존 JDBC에서는 DB를 다루려고 할 때,
- PreparedStatement
- ResultSet
- Connection
이 세 가지 객체를 따로 다루며 DB에 접근한다.
Connection으로 DB정보를 불러오고, PreparedStatement로 쿼리문에 들어갈 인자를 작성하고, Resultset으로 쿼리실행의 결과값을 가져와 저장하고.. 객체 하나하나 연결을 종료( close() )하는 등... 코드가 굉장히 길어지게 된다.
하지만 스프링 프레임워크에서는 'JdbcTemplate'를 활용하여 더욱 간편하게 DB를 다룰 수 있게 되는데, 이름에서도 알 수 있듯이 JDBC를 위한 템플릿, JDBC를 위한 틀(형식) 이라는 의미다.
1.1. 기존 Jdbc와 JdbcTemplate의 비교 ( select문 )
▶ 기존 JDBC
@Repository
public class MemberDao {
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
@Autowired
DataBaseManager dbm;
public MemberDto getMember(String id) {
MemberDto mdto = null;
con = dbm.getConnection();
String sql = "select * from member where userid=?";
try {
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery();
if(rs.next()) {
mdto = new MemberDto();
mdto.setUserid(id);
mdto.setPwd(rs.getString("pwd"));
mdto.setName(rs.getString("name"));
mdto.setEmail(rs.getString("email"));
mdto.setPhone(rs.getString("phone"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
dbm.close(con, pstmt, rs);
}
return mdto;
}
//...
}
▶ JdbcTemplate
: JdbcTemplate에서는 select 쿼리문을 다룰 시 'query() 메서드'를 사용하게 된다.
@Repository
public class ProductDao {
private JdbcTemplate template;
@Autowired
public ProductDao(ComboPooledDataSource dataSource) {
this.template = new JdbcTemplate(dataSource);
}
//...
public ProductVO getProduct(int pseq) {
String sql = "select * from product where pseq = ?";
List<ProductVO> list = template.query(sql, new RowMapper<ProductVO>() {
@Override
public ProductVO mapRow(ResultSet rs, int rowNum) throws SQLException {
ProductVO pvo = new ProductVO();
pvo.setPseq(rs.getInt("pseq"));
pvo.setIndate(rs.getTimestamp("indate"));
pvo.setName(rs.getString("name"));
pvo.setPrice1(rs.getInt("price1"));
pvo.setPrice2(rs.getInt("price2"));
pvo.setImage(rs.getString("image"));
pvo.setUseyn(rs.getString("useyn"));
pvo.setBestyn(rs.getString("bestyn"));
pvo.setContent(rs.getString("content"));
return pvo;
}
},pseq);
return list.get(0);
}
//...
}
1.2. 기존 Jdbc와 JdbcTemplate의 비교 ( Insert, update, delete문 )
▶ 기존 JDBC
@Repository
public class MemberDao {
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
@Autowired
DataBaseManager dbm;
public void insert(BoardDto bdto) {
String sql ="insert into board(num, pass, userid, email, title, content, imgfilename) "
+ " values(board_seq.nextVal, ?,?,?,?,?,?)";
con = dbm.getConnection();
try {
pstmt = con.prepareStatement(sql);
pstmt.setString(1, bdto.getPass());
pstmt.setString(2, bdto.getUserid());
pstmt.setString(3, bdto.getEmail());
pstmt.setString(4, bdto.getTitle());
pstmt.setString(5, bdto.getContent());
pstmt.setString(6, bdto.getImgfilename());
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
dbm.close(con, pstmt, rs);
}
}
//...
}
▶ JdbcTemplate
: insert, update, delete문을 다룰 시에는 query()메서드가 아닌, 'update() 메서드'를 사용하게 되는데,
상대적으로 코드가 간결하고, 간편해진다.
@Repository
public class MemberDao {
private JdbcTemplate template;
@Autowired
public MemberDao(ComboPooledDataSource dataSource) {
this.template = new JdbcTemplate(dataSource);
}
public void update(MemberVO mvo) {
String sql = "update member set pwd=?, name=?, zip_num=?, address=?, address2=?, email=?, phone=? "
+ " where userid=?";
template.update(sql, mvo.getPwd(), mvo.getName(), mvo.getZip_num(),
mvo.getAddress(), mvo.getAddress2(),mvo.getEmail(), mvo.getPhone(), mvo.getUserid());
}
}
2. JdbcTemplate 사용 준비
2.1. context에 dataSource 빈 추가
c3p0 외부 라이브러리 ComboPooledDataSource 객체를 사용하여
DB드라이버, url 등 그리고, DBCP정보까지 추가한 dataSource 빈을 생성한다.
//...
<!-- mchange, c3p0 -->
<beans:bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<beans:property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>
<beans:property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:xe"/>
<beans:property name="user" value="scott"/>
<beans:property name="password" value="tiger"/>
<beans:property name="maxPoolSize" value="200"/>
<beans:property name="checkoutTimeout" value="60000"/>
<beans:property name="maxIdleTime" value="1800"/>
<beans:property name="idleConnectionTestPeriod" value="600"/>
</beans:bean>
//...
2.2. Dao에서 Bean 주입
- JdbcTemplate 객체를 멤버변수에 생성
- @Autowired 어노테이션을 사용해 DAO생성자의 매개변수로 ComboPooledDataSource 객체가 주입되고,
- 이것을 this.template에 new JdbcTemplate의 인수로 주입한다.
@Repository
public class MemberDao {
private JdbcTemplate template;
@Autowired
public MemberDao(ComboPooledDataSource dataSource) {
this.template = new JdbcTemplate(dataSource);
}
//...
}
3. JdbcTemplate 사용법
3.1. query() 메서드
query() 메서드는 select 쿼리를 지원하는 메서드이다.
3.1.1. RowMapper<T> 인터페이스
ResultSet으로 가져온 쿼리 결과값을 원하는 형태( <T> )의 객체?로 변환하는 기능을 제공한다.
위에서 본 코드를 다시 살펴보면, JdbcTemplate.query()의 전달인수로 쿼리문, new RowMapper<T>(){ ... }, 쿼리에 들어갈 변수가 들어간다.
new RowMapper의 구현부에는 구현되지 않은 추상메서드( mapRow( ) )가 구현되는데 여기에서 ResultSet 객체를 사용하여 쿼리에서의 결과를 DTO객체에 주입하여 반환하면 된다.
@Repository
public class ProductDao {
private JdbcTemplate template;
@Autowired
public ProductDao(ComboPooledDataSource dataSource) {
this.template = new JdbcTemplate(dataSource);
}
//...
public ProductVO getProduct(int pseq) {
String sql = "select * from product where pseq = ?";
List<ProductVO> list = template.query(sql, new RowMapper<ProductVO>() {
@Override
public ProductVO mapRow(ResultSet rs, int rowNum) throws SQLException {
ProductVO pvo = new ProductVO();
pvo.setPseq(rs.getInt("pseq"));
pvo.setIndate(rs.getTimestamp("indate"));
pvo.setName(rs.getString("name"));
pvo.setPrice1(rs.getInt("price1"));
pvo.setPrice2(rs.getInt("price2"));
pvo.setImage(rs.getString("image"));
pvo.setUseyn(rs.getString("useyn"));
pvo.setBestyn(rs.getString("bestyn"));
pvo.setContent(rs.getString("content"));
return pvo;
}
},pseq);
return list.get(0);
}
//...
}
3.2. update() 메서드
update() 메서드는 update, insert, delete 쿼리를 지원하는 메서드이다.
@Repository
public class MemberDao {
private JdbcTemplate template;
@Autowired
public MemberDao(ComboPooledDataSource dataSource) {
this.template = new JdbcTemplate(dataSource);
}
public void update(MemberVO mvo) {
String sql = "update member set pwd=?, name=?, zip_num=?, address=?, address2=?, email=?, phone=? "
+ " where userid=?";
template.update(sql, mvo.getPwd(), mvo.getName(), mvo.getZip_num(),
mvo.getAddress(), mvo.getAddress2(),mvo.getEmail(), mvo.getPhone(), mvo.getUserid());
}
}
JdbcTemplate.query() 메서드 보다는 한결 간결하다.
전달인수로 들어가는 것은 쿼리문, 쿼리문에 들어갈 변수들이 들어간다.
참고 링크 :
https://velog.io/@seculoper235/RowMapper%EC%97%90-%EB%8C%80%ED%95%B4
https://pangtrue.tistory.com/81