본문 바로가기
개발 공부/Spring

[Spring] 스프링의 JDBC - jdbcTemplate

by sngynhy 2021. 10. 11.

JDBC 사용 시 SQL 구문만 조금씩 달라질 뿐 전체적인 자바 코드의 구조는 유사하다.

따라서 DAO가 추가될 때마다 비슷한 코드 작성을 반복해야한다.

스프링에서는 이러한 반복되는 코드 사용을 줄이기 위해 jdbcTemplate을 지원해준다.

jdbcTemplate

템플릿 메서드 패턴이 적용된 클래스
템플릿 메서드 패턴이란? 반복되는 로직을 캡슐화시켜 재사용하는 패턴

 

jdbcTemplate 사용을 위한 설정

1. pom.xml 설정 파일에 jdbcTemplate 의존성 주입

<!-- DBCP - jdbcTemplate 사용을 위한 설정 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>${org.springframework-version}</version>
</dependency>
<dependency>
	<groupId>commons-dbcp</groupId>
	<artifactId>commons-dbcp</artifactId>
	<version>1.4</version>
</dependency>

 

2. applicationContext.xml 설정 파일에 "Datasource"를 스프링 컨테이너가 만들 수 있도록 설정

<!-- bean으로 Datasource 객체 등록 -->
<!-- 객체를 해제하는 시점에 자동 반납을 위하여 destroy-method="colse" 처리 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
	<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"></property>
	<property name="username" value="sngynhy"></property>
	<property name="password" value="qwer"></property>
</bean>

jdbcTemplate 사용 방법

1. update() : insert, delete, update sql 구문을 처리할 때 호출 (JDBC의 executeUpdate()와 같은 역할)

쿼리문의 ?에 들어갈 값을 전달하는 것이 핵심

 

? 값 전달 방법

1-1) ? 안에 들어갈 값을 순서대로 나열하여 작성

1-2) ? 안에 들어갈 값을 Object 배열로 만들어서 전달

 

예제)

private final String updateSQL = "update board set title = ?, content = ? where wpk = ?";

public void updateBoard(BoardVO invo) {
			
		conn = JDBC.getConnection();
		
		try {
			pstmt = conn.prepareStatement(updateSQL);
			pstmt.setString(1, invo.getTitle());
			pstmt.setString(2, invo.getContent());
			pstmt.setInt(3, invo.getWpk());
			pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBC.close(conn, pstmt);
		}
	}

 

1-1) ? 안에 들어갈 값을 순서대로 나열하여 작성

private final String updateSQL = "update board set title = ?, content = ? where wpk = ?";

public void updateBoard(BoardVO invo) {
	int cnt = jdbcTemplate.update(updateSQL, ?,?,?);
    // cnt : sql문이 수행된 row 개수
}

 

1-2) ? 안에 들어갈 값을 Object 배열로 만들어서 전달

private final String updateSQL = "update board set title = ?, content = ? where wpk = ?";

public void updateBoard(BoardVO invo) {
	Object[] args = {?,?,?};
    int cnt = jdbcTemplate.update(updateSQL, args);
}

 

2. queryForInt() : select sql 구문을 처리할 때 호출

select 구문 중에서도 정수 값이 검색된 경우에 사용 (주로 sql의 count()함수와 사용)

ex) select count(*) from board;

 

3. queryForObject() : select sql 구문의 처리 결과가 단 한 개일 때 호출 (selectOne)

만약 결과가 없거나 2개 이상인 경우 예외 발생!

DBMS에서 sql 구문으로 검색된 결과는 자바 객체가 아니다.

sql 구문의 처리 결과를 자바 객체로 만들기 위해 ( -- [매핑] --> ) VO(Value Object)를 만들어 사용하는데

jdbcTemplate 사용 시 매핑을 위한 ★RowMapper 설정이 필요★하다. (테이블마다 설정 필요!)

즉, Integer, String은 컴파일러가 해당 타입에 맞게 알아서 매핑해주지만 우리가 만든 객체는 알 수 없기 때문에

직접 Mapping Logic을 구현해야 한다.

-> 각 테이블에 대한 RowMapper는 RowMapper 인터페이스를 상속받아 class로 구현!

 

매핑 시 필요한 정보

3-1. 누구랑 매핑할지 -> 어떤 VO랑 매핑할지

3-2. 어떻게 매핑할지 -> 어떤 방식으로 매핑할지

 

예제)

public BoardVO getData(BoardVO vo) {
	return jdbcTemplate.queryForObject(sql구문, args, new RowMapper());
	// new RowMapper() 는 각 테이블에 대한 매퍼기 때문에 new BoardRowMapper() 형식으로 작성
}

 

 

 

4. query() : select sql 구문의 처리 결과가 List일 때 호출 (selectALL)

예제)

public List<BoardVO> getDataList(BoardVO vo) {
	return jdbcTemplate.query(sql구문, [args], new RowMapper());
	// [args]는 생략 가능
}

 

jdbcTempalte 사용하기

방법1) Support 상속 받아 사용하는 방법

// BoardRowMapper는 RowMapper 인터페이스를 상속받아 class로 구현
class BoardRowMapper implements RowMapper<BoardVO> {
	@Override
	public BoardVO mapRow(ResultSet rs, int rowNum) throws SQLException {
		BoardVO outvo = new BoardVO();
		outvo.setWpk(rs.getInt("wpk"));
		outvo.setTitle(rs.getString("title"));
		outvo.setWriter(rs.getString("writer"));
		outvo.setContent(rs.getString("content"));
		outvo.setWdate(rs.getDate("wdate"));
		return outvo;
	}
}

// 방법1. extends 상속 받아서 구현★
@Repository
public class SpringBoardDAO1 extends JdbcDaoSupport{
	
	private final String insertSQL = "insert into board (wpk, title, writer, content) values (nvl((select max(wpk) from board),0)+1, ?, ?, ?)";
	private final String updateSQL = "update board set title = ?, content = ? where wpk = ?";
	private final String deleteSQL = "delete board where wpk = ?";
	private final String getBoardListSQL = "select * from board";
	private final String getBoardSQL = "select * from board where wpk = ?";
	
	// DataSource 받아오기
	@Autowired // ★
	public void setSuperDataSource(DataSource dataSouce) {
		super.setDataSource(dataSouce);
	}
	
	public void insertBoard(BoardVO invo) {
		System.out.println("jdbcTemplate으로 insert");
		getJdbcTemplate().update(insertSQL, invo.getTitle(), invo.getWriter(), invo.getContent());
	}
	
	public void updateBoard(BoardVO invo) {
		System.out.println("jdbcTemplate으로 update");
		getJdbcTemplate().update(updateSQL, invo.getTitle(), invo.getContent(), invo.getWpk());
	}
	
	public void deleteBoard(BoardVO invo) {
		System.out.println("jdbcTemplate으로 delete");
		getJdbcTemplate().update(deleteSQL, invo.getWpk());
	}
	public List<BoardVO> getBoardList(BoardVO invo) {
		System.out.println("jdbcTemplate으로 getBoardList");
		return getJdbcTemplate().query(getBoardListSQL, new BoardRowMapper());

	}
	public BoardVO getBoard(BoardVO invo) {
		System.out.println("jdbcTemplate으로 getBoard");
		Object[] args = {invo.getWpk()};
		return getJdbcTemplate().queryForObject(getBoardSQL, args, new BoardRowMapper());
		
	}
	
}

 

applicationContext.xml에 bean 추가

<!-- bean으로 Datasource 객체 등록 -->
<!-- 객체를 해제하는 시점에 자동 반납을 위하여 destroy-method="colse" 처리 -->
<bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource" destroy-method="close">
	<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
	<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
	<property name="username" value="sngynhy"/>
	<property name="password" value="qwer"/>
</bean>

 

방법2) <bean> 주입하여 사용하는 방법

// BoardRowMapper는 RowMapper 인터페이스를 상속받아 class로 구현
class BoardRowMapper implements RowMapper<BoardVO> {
	@Override
	public BoardVO mapRow(ResultSet rs, int rowNum) throws SQLException {
		BoardVO outvo = new BoardVO();
		outvo.setWpk(rs.getInt("wpk"));
		outvo.setTitle(rs.getString("title"));
		outvo.setWriter(rs.getString("writer"));
		outvo.setContent(rs.getString("content"));
		outvo.setWdate(rs.getDate("wdate"));
		return outvo;
	}
}

//방법2. jdbcTemplate객체를 <bean>으로 등록하여 의존성 주입받아 사용★ (사용 빈도 높음)
public class SpringBoardDAO2 {
	
	private final String insertSQL = "insert into board (wpk, title, writer, content) values (nvl((select max(wpk) from board),0)+1, ?, ?, ?)";
	private final String updateSQL = "update board set title = ?, content = ? where wpk = ?";
	private final String deleteSQL = "delete board where wpk = ?";
	private final String getBoardListSQL = "select * from board";
	private final String getBoardSQL = "select * from board where wpk = ?";
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public void insertBoard(BoardVO invo) {
		System.out.println("jdbcTemplate으로 insert");
		jdbcTemplate.update(insertSQL, invo.getTitle(), invo.getWriter(), invo.getContent());
	}
	public void updateBoard(BoardVO invo) {
		System.out.println("jdbcTemplate으로 update");
		jdbcTemplate.update(updateSQL, invo.getTitle(), invo.getContent(), invo.getWpk());
	}
	public void deleteBoard(BoardVO invo) {
		System.out.println("jdbcTemplate으로 delete");
		jdbcTemplate.update(deleteSQL, invo.getWpk());
	}
	public List<BoardVO> getBoardList(BoardVO invo) {
		System.out.println("jdbcTemplate으로 getBoardList");
		return jdbcTemplate.query(getBoardListSQL, new BoardRowMapper());

	}
	public BoardVO getBoard(BoardVO invo) {
		System.out.println("jdbcTemplate으로 getBoard");
		Object[] args = {invo.getWpk()};
		return jdbcTemplate.queryForObject(getBoardSQL, args, new BoardRowMapper());
		
	}
}

 

applicationContext.xml에 bean 추가

Datasource 객체를 먼저 등록 후 이를 참조하여 jdbcTemplate 객체를 등록한다. 

<!-- bean으로 Datasource 객체 등록 -->
<!-- 객체를 해제하는 시점에 자동 반납을 위하여 destroy-method="colse" 처리 -->
<bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource" destroy-method="close">
	<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
	<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
	<property name="username" value="sngynhy"/>
	<property name="password" value="qwer"/>
</bean>

<!-- jdbcTemplate 객체 등록 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" destroy-method="close">
	<property name="dataSource" ref="dataSource"></property>
</bean>

 

'개발 공부 > Spring' 카테고리의 다른 글

[Spring] 다국어 처리  (0) 2021.10.28
[Spring] 트랜잭션 관리자 설정  (0) 2021.10.13
[Spring] 바인드 변수  (0) 2021.10.07
[Spring] AOP  (0) 2021.10.04
[JAVA] 싱글톤 패턴  (0) 2021.10.03