Spring/Spring

day68) Spring - Model 설계2 : JDBC Template

code_learner 2022. 4. 7. 00:46

https://code-learning.tistory.com/106?category=1011627 

 

day62) Spring - Model 설계

[기본적인 게시판 CRUD를 활용한 Spring Framework 모델구조 만들기] -com.test.app.board 패키지에서는 객체화 되어 사용되지 않는 클래스 :BoardService(interface), BoardVO -com.test.app.board.impl 패키지에..

code-learning.tistory.com

 

[JDBC template이란?]

-템플릿 패턴

동일하진 않지만, 유사한 코드가 반복되는 패턴에서 사용되는 패턴을 템플릿 패턴이라고 부른다.

템플릿 패턴을 사용하게 된다면 반복되거나 복잡한 알고리즘을 캡슐화하게 되어 재사용성이 증가한다.

 

 

: 위에 제공한 주소에서는 JDBCUtil클래스를 통해 공통로직을 빼서 사용했다.

: 하지만 유사하게 반복되는코드들이 너무 많기 때문에 이를 JDBCTemplate으로 맡겨보자

=> JDBCTemplate

: 유사하게 반복되는 DB관련로직을 Template클래스에서 제공받고, 
  개발자는 설정, 설정값(SQL구문, 매핑)들만 신경쓰면 된다.

 


[사용방법]

1. 라이브러리 추가: pom.xml에 설정 추가

<!-- 스프링 JDBC를 위한 DBCP -->
      <dependency><!--1-->
         <groupId>commons-dbcp</groupId>
         <artifactId>commons-dbcp</artifactId>
         <version>1.4</version>
      </dependency>
      <dependency><!--2-->
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
            <version>${org.springframework-version}</version>
      </dependency>

1번만 사용해도 잘 적용이 되는 사람이 있는데 나는 1번만으로는 안되서 2번까지 추가해서 사용했다.

DBCP는 커넥션을 확보하여 커넥션 풀을 생성하는데 목적이 있다.

 

-> 이미 여러개 연결되어있는 커넥션들의 풀을 dbcp가 가지고 있고, sql문을 사용할 일이 생겼을 때 확보해둔 커넥션을 사용자에게 제공하고, 사용자가 사용을 마쳤다면 원래대로 돌려놓는 방식

-> 다중 사용자 이용시 이점이 있다.

 

2. DataSource 생성 - applicationContext.xml에서 객체 생성

JDBCTemplate이 DB연동을 하려면 커넥션을 확보해야한다.
JDBCTemplate이 사용할 DataSource를 스프링 컨테이너가 생성할 수 있도록 <bean>해주어야한다.

	<!-- DataSource 설정 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<!-- destroy-method="close": 연결해제 메서드 -->
		<!-- setter injection -->
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
		<property name="username" value="kim" />
		<property name="password" value="1234" />
	</bean>

 

3.DAO 생성

1) JDBCTemplate을 applicationContext.xml에서<bean>으로 생성하여 위에서 생성한 dataSource를 DI한다.

	<!-- JdbcTemplate 생성 -->
   <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
      <property name="dataSource" ref="dataSource" />
   </bean>
   
   
   <context:component-scan base-package="com.test.app" />

 

2) DAO사용하기

package com.test.app.board.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.test.app.board.BoardVO;

@Repository("boardDAO")
public class BoardDAO2 {
	// Spring에서 제공하는 JDBC.JDBCTemplate
	// JDBCTemplate을 <bean>으로 생성해서 DI주입해서 사용 ★
	@Autowired//타입을 보고 일치하는 생성된 객체와 mapping한다
	private JdbcTemplate jdbcTemplate;

	private final String BOARD_INSERT="insert into board values((select nvl(max(bid),0)+1 from board),?,?,?)";
	private final String BOARD_SELECTONE="select * from board where bid=?";
	private final String BOARD_SELECTALL="select * from board order by bid desc";
	private final String BOARD_UPDATE="update board set title=?,content=? where bid=?";
	private final String BOARD_DELETE="delete board where bid=?";

	public void insertBoard(BoardVO vo) {
		System.out.println("insertBoard() 호출됨");
		jdbcTemplate.update(BOARD_INSERT, vo.getTitle(),vo.getWriter(),vo.getContent());
	}
	public BoardVO getBoard(BoardVO vo) {
		System.out.println("getBoard() 호출됨");
		Object[] args= {vo.getBid()};

		//BoardRowMapper()-> 어떻게 연결할 것인가
		return jdbcTemplate.queryForObject(BOARD_SELECTONE, args, new BoardRowMapper());
	}

	// 검색을 위한 비즈니스 메서드를 따로 작성xxx
	// 인자변경 -> 불리점 => VO에 멤버변수로 추가!
	public List<BoardVO> getBoardList(BoardVO vo) {
		System.out.println("getBoardList() 호출됨");
		return jdbcTemplate.query(BOARD_SELECTALL, new BoardRowMapper());
	}
	public void updateBoard(BoardVO vo) {
		jdbcTemplate.update(BOARD_UPDATE, vo.getTitle(),vo.getContent(),vo.getBid());
	}
	public void deleteBoard(BoardVO vo) {
		jdbcTemplate.update(BOARD_DELETE, vo.getBid());
	}

}
class BoardRowMapper implements RowMapper<BoardVO> {

	@Override
	public BoardVO mapRow(ResultSet rs, int rowNum) throws SQLException {
		BoardVO data=new BoardVO();
		data.setBid(rs.getInt("bid"));
		data.setContent(rs.getString("content"));
		data.setTitle(rs.getString("title"));
		data.setWriter(rs.getString("writer"));
		return data;
	}

}

 

[JDBC Template에서 사용하는 메서드]


1) update()

INSERT, UPDATE, DELETE를 수행할 때 활용한다 

이때 ?를 처리하는 방법으로 2가지가 있다.
- 인자를 직접, 각각 연결

   jdbcTemplate.update(SQL, vo.getxxx(),vo.getxxx(),...);

- 배열에 저장하여 한번에 연결

  Object[] args={vo.getxxx(), vo.getxxx(), ...};
  jdbcTemplate.update(SQL, args);

 


2) queryForInt(): 정수 output에 대해 사용한다.
SELECT : SELECT COUNT(*) FROM 테이블 WHERE 조건절;

 


3) queryForObject() : 객체 output에 사용

SELECT * FROM 테이블명 WHERE 조건절;
SELECT : 검색결과가 하나일 때 사용한다.

 

☆검색 결과가 없거나, 두개 이상이면 예외발생! ex)로그인


검색결과 -> 자버객체(VO) 설정필요!!! => RowMapper 
RowMapper :어떤 테이블의 결과를 어떤 VO로 볼지에 대한 설정
테이블:VO=1:1이여야 한다.

 


4)query()

SELECT * FROM 테이블명 WHERE 조건절;
SELECT : 검색결과가 여러개(List)일 때 사용한다
RowMapper를 검색결과만큼 사용함 == mapRow()를 검색결과만큼 호출
사용결과를 List에 저장하여 보내준다.