Programming/기초 지식

Spring) JdbcTemplate ( query( ), update( ), RowMapper<T> )

반응형

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 주입

  1. JdbcTemplate 객체를 멤버변수에 생성
  2. @Autowired 어노테이션을 사용해 DAO생성자의 매개변수로 ComboPooledDataSource 객체가 주입되고,
  3. 이것을 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

 

RowMapper에 대해!

앞에서 말하길 queryForObject의 반환형은 데이터형만 가능하다고 했다.하지만 말도 안된다.그럼 "SELECT \* FROM USER" 구문으로 User 객체 자체를 반환받는건 포기해야 하는걸까?그걸 위해서 필요한 것이

velog.io

https://pangtrue.tistory.com/81

 

[Spring JDBC] JdbcTemplate 클래스

1. JdbcTemplate이란? Spring Framework로 앱을 제작할 때 Data Access Layer에서 사용하는 기술은 크게 3가지입니다. 1. JPA (구현체로 Hibernate를 많이 사용합니다.) 2. MyBatis (구 iBatis) 3. JdbcTemplate..

pangtrue.tistory.com

 

반응형