본문 바로가기
백엔드/Spring Framework

JDBC Template

by maverick11471 2024. 7. 12.

[요약]

 - DB를 활용해서 SQL문을 JAVA 언어로 사용할 수 있다.

 

1. JDBC Template 정의

- GoF의 디자인 패턴 중 템플릿 디자인 패턴이 적용된 클래스
- 템플릿 디자인 패턴: 반복되는 작업을 캡슐화하여 재사용할 수 있는 패턴으로 정의하는 방식
- DBCP(DataBase Connection Pool)에 DataSource(DB 연결 정보 객체)을 의존성으로 주입받아서 
  커넥션의 풀을 구성하고 커넥션들을 계속 대여하여 재사용할 수 있는 방식
  
  [결론] 이걸 왜하냐?
  try~catch~finally 구문을 할 필요 없이 JDBC Template를 이용하여 계속 사용

 

 

2. JDBC Template 사용가능 메소드

 [1번 방식] update(): insert, update, delete 쿼리 실행

update(쿼리문, 물음표인자값1, 물음표인자값2, 물음표인자값3);

 

 [2번 방식] 물음표 인자 개수만큼 배열을 생성하여 배열 자체를 매개변수로 보내는 방식

Object[] args = {물음표인자값1, 물음표인자값2, 물음표인자값3};
update(쿼리문, args);

 

 [다른 메소드]

queryForInt() : 결과값이 정수(sum, count, avg)
queryForObject() : RowMapper라는 인터페이스를 상속받아 구현한 클래스를 리턴
                   mapRow() 라는 메소드를 구현해서 개별자가 원하는 형태의 객체로 만들어 리턴
query() : 다중행일때 사용. 사용법은 queryForObject()와 동일.

 


3. db.properties 파일 작성

 * jdbc 연결을 외부 파일로 작성하여 가져오는 방식으로 시행

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/studydb?serverTimezone=UTC
jdbc.username=(설정한 id)
jdbc.password=(설정한 비밀번호)

4. root-context.xml 수정

 가. JDBC 연결을 위한 객체 생성

 나. JDBC Template bean 객체 등록

    <!--외부 파일 참조-->
    // classpath: main에 있는 폴더를 찾게 됨
    <context:property-placeholder location="classpath:/config/db.properties"/>

    <!--라이브러리(jar 파일)의 클래스에는 어노테이션을 달 수 없기때문에 bean 엘리먼트를 통해서 bean 객체를 생성하고 등록한다.-->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
    // ${}를 이용해서 외부파일(db.properties)에서 key값을 가져옴.
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

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

 


5. pom.xml : JDBC Template bean 객체 등록(MVN REPOSITORY 사이트 검색)

        <!--JDBC Template 의존성 주입-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>

6. BoardRowMapper 클래스 생성

 - RowMapper 인터페이스 상속

 - mapRow 메소드 구현 -> 개발자가 원하는 형태의 객체로 만들어 리턴

public class BoardRowMapper implements RowMapper<BoardDto> {
    @Override
    public BoardDto mapRow(ResultSet rs, int rowNum) {
        BoardDto boardDto = new BoardDto();

        try {
            boardDto.setId(rs.getInt("ID"));
            boardDto.setTitle(rs.getString("TITLE"));
            boardDto.setContent(rs.getString("CONTENT"));
            boardDto.setWRITER_ID(rs.getInt("WRITER_ID"));
            boardDto.setNickname(rs.getString("NICKNAME"));
            boardDto.setRegdate(rs.getTimestamp("REGDATE").toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime());
            boardDto.setModdate(rs.getTimestamp("MODDATE").toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime());
            boardDto.setCnt(rs.getInt("CNT"));
        } catch(SQLException se) {
            System.out.println(se.getMessage());
        }

        return boardDto;
    }

 


7. JDBC Template 구현방법 (2가지)

 가. JdbcDaoSuppor 상속

 나. JdbcTemplate 필드 선언

2가지 방법의 차이점
1. JdbcDaoSupport는 DAO 클래스를 작성할 때 JdbcTemplate을 쉽게 사용할 수 있도록 도와주는 추상 클래스입니다.
이 두 가지를 적절하게 사용하면 Spring 환경에서 효율적으로 데이터베이스 작업을 수행할 수 있습니다.
2. JdbcTemplate은 직접 JDBC 작업을 간편하게 처리할 수 있는 도구입니다.

 

 

① : JdbcDaoSupport 클래스 상속받아 사용 -> "2. JDBC Template 사용가능 메소드" 참고

 - 리턴값이 없을 때: getJdbcTemplate().update(쿼리문, 물음표인자값..)

 - 리턴값이 List일때: boardDtoList = getJdbcTemplate().query(쿼리문, new BoardRowMapper());

 - 리턴값이 단행문일때: boardDto = getJdbcTemplate().queryForObject(쿼리문, args, new BoardRowMapper());

    * 중요: queryForObject에서 args 매개변수를 사용할 때는 Object 배열 형태여야 한다. 

                -> Object[] args = {id};

@Repository
// JdbcDaoSupport 상속
public class FreeBoardDaoJdbcDaoSupport extends JdbcDaoSupport {

// setSuperDataSource 메서드 사용
	@Autowired
    public void setSuperDataSource(DataSource dataSource) {
        super.setDataSource(dataSource);
    }

(쿼리문 동일)...

public void post(BoardDto boardDto) {
        System.out.println("FreeBoardDao의 post 메소드 실행");

        getJdbcTemplate().update(POST, boardDto.getTitle(), boardDto.getContent(), boardDto.getWRITER_ID());

        System.out.println("FreeBoardDao의 post 메소드 실행 종료");
    }

    public void modify(BoardDto boardDto) {
        System.out.println("FreeBoardDao의 modify 메소드 실행");

        getJdbcTemplate().update(MODIFY, boardDto.getTitle(), boardDto.getContent(), boardDto.getModdate().toString(), boardDto.getId());

        System.out.println("FreeBoardDao의 modify 메소드 실행 종료");
    }

    public List<BoardDto> getBoardList() {
        System.out.println("FreeBoardDao의 getBoardList 메소드 실행");

        List<BoardDto> boardDtoList = new ArrayList<>();

        boardDtoList = getJdbcTemplate().query(GET_BOARD_LIST, new BoardRowMapper());

        System.out.println("FreeBoardDao의 getBoardList 메소드 실행 종료");
        return boardDtoList;
    }

    public void delete(int id) {
        System.out.println("FreeBoardDao의 delete 메소드 실행");

        getJdbcTemplate().update(DELETE, id);

        System.out.println("FreeBoardDao의 delete 메소드 실행 종료");
    }
    
    public BoardDto getBoard(int id) {
        System.out.println("FreeBoardDao의 getBoard 메소드 실행");

        BoardDto boardDto = new BoardDto();

        // queryForObject의 두 번째 매개변수는 Object 배열 형태여야한다.
        Object[] args = {id};

        boardDto = getJdbcTemplate().queryForObject(GET_BOARD, args, new BoardRowMapper());

        System.out.println("FreeBoardDao의 getBoard 메소드 실행 종료");
        return boardDto;
    }

 

- 결과

 

 

②  : JdbcTemplate을 필드로 선언하고 의존성을 주입받아서 사용하는 방식

 - JdbcTemplate 필드 선언

 - 리턴값이 없을 때: jdbcTemplate().update(쿼리문, 물음표인자값..)

 - 리턴값이 List일때: boardDtoList = jdbcTemplate().query(쿼리문, new BoardRowMapper());

 - 리턴값이 단행문일때: boardDto = jdbcTemplate().queryForObject(쿼리문, args, new BoardRowMapper());

    * 중요: queryForObject에서 args 매개변수를 사용할 때는 Object 배열 형태여야 한다. 

                -> Object[] args = {id};

@Repository
public class FreeBoardDao {
    private JdbcTemplate jdbcTemplate;

    @Autowired
    public FreeBoardDao(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    ... 쿼리 동일
    
    
    public void post(BoardDto boardDto) {
        System.out.println("FreeBoardDao의 post 메소드 실행");

        jdbcTemplate.update(POST, boardDto.getTitle(), boardDto.getContent(), boardDto.getWRITER_ID());

        System.out.println("FreeBoardDao의 post 메소드 실행 종료");
    }

    public void modify(BoardDto boardDto) {
        System.out.println("FreeBoardDao의 modify 메소드 실행");

        jdbcTemplate.update(MODIFY, boardDto.getTitle(), boardDto.getContent(), boardDto.getModdate().toString(), boardDto.getId());

        System.out.println("FreeBoardDao의 modify 메소드 실행 종료");
    }

    public List<BoardDto> getBoardList() {
        System.out.println("FreeBoardDao의 getBoardList 메소드 실행");

        List<BoardDto> boardDtoList = new ArrayList<>();

        boardDtoList = jdbcTemplate.query(GET_BOARD_LIST, new BoardRowMapper());

        System.out.println("FreeBoardDao의 getBoardList 메소드 실행 종료");
        return boardDtoList;
    }

    public void delete(int id) {
        System.out.println("FreeBoardDao의 delete 메소드 실행");

        jdbcTemplate.update(DELETE, id);

        System.out.println("FreeBoardDao의 delete 메소드 실행 종료");
    }
    
    public BoardDto getBoard(int id) {
        System.out.println("FreeBoardDao의 getBoard 메소드 실행");

        BoardDto boardDto = new BoardDto();

        // queryForObject의 두 번째 매개변수는 Object 배열 형태여야한다.
        Object[] args = {id};

        boardDto = jdbcTemplate.queryForObject(GET_BOARD, args, new BoardRowMapper());

        System.out.println("FreeBoardDao의 getBoard 메소드 실행 종료");
        return boardDto;
    }