[Spring] JdbcDaoSupport 클래스

김대현·2024년 10월 16일

📚 공부_Spring

목록 보기
3/8

목차

1. JdbcDaoSupport 클래스란?
2. JdbcDaoSupport 를 활용한 DB연결 과정
3. 마무리

1. JdbcDaoSupport 클래스란?

Spring에서 Database에 접근해 데이터를 가져오는 방법은 크게 4가지가 있다.

  1. jdbc class를 사용
  2. JdbcDaoSupport를 사용
  3. Mybatis 사용
  4. JPA(hibernate) 사용
즉 JdbcDaoSupport는 Database와의 접근을 위해 Spring Framework에서 제공하는 클래스 이다.

jdbcDaoSupport 클래스를 자세히 알아보자

Spring 공식 홈페이지에서 제공하는 api를 통해서 jdbcDaoSupport를 검색해 보면 위와 같은 정보를 확인해 볼 수 있다. 우선 jdbcDaoSupport는 추상 클래스로 DaoSupport 클래스를 상속받은 서브클래스임을 알 수 있다.

jdbcDaoSupport 클래스의 주요 멤버

이름 설명
createJdbcTemplate(DataSource dataSource) 주어진 DataSource에 대한 JdbcTemplate을 생성
getJdbcTemplate() DataSource로 미리 초기화되거나 명시적으로 설정된 이 DAO에 대한 JdbcTemplate을 반환
Getter Method
getDataSource()) 이 DAO에서 사용하는 JDBC DataSource를 반환
Getter method
setDataSource(DataSource dataSource) 이 DAO에서 사용할 JDBC DataSource를 설정합니다.
Setter method

위의 멤버 메소드들을 자세히 보면 지속적으로 반복되어 사용되는 타입이 나온다. 그것은 바로 DataSource 이다. 즉 JdbcDaoSupport 클래스를 이해기 위해서는 DataSource를 이해해야만 한다.

DataSource 인터페이스는 무엇인가?

(출처 : https://mr-popo.tistory.com/101)

DataSource 인터페이스는 커넥션을 획득하는 방법을 추상화 한 인터페이스이며 Java에서 제공하는 표준 인터페이스(javax.sql.DataSource)이다. DataSource 인터페이스의 핵심 기능은 커넥션 조회밖에 없다.

2. JdbcDaoSupport 를 활용한 DB연결 과정

JdbcDaoSupport 클래스를 사용해서 DB를 연결하는 방법에는 크게 2가지가 있다. 하나는 XML을 통해서 DB의 설정을 하는 방법이고 나머지는 Class에 DB의 설정을 하고 annotation으로 연결하는 방법이다. 블로그에는 annotation을 활용해서 연결하는 과정을 기록하고자 한다.

1) DB세팅

//DB를 세팅하는 Class
package pack;

import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.stereotype.Component;

@Component
public class DataSource extends DriverManagerDataSource{
	public DataSource() {
	    //mariadb-java-client 에서 제공하는 클래스
		setDriverClassName("org.mariadb.jdbc.Driver"); 
		setUrl("jdbc:mariadb://localhost:3306/테이블명");
		setUsername("유저아이디");
		setPassword("비밀번호");
	}
}

별개의 클래스에 DB의 세팅을 위와 같이 할 수 있다. 이 때에 주의해서 봐야하는 부분은 DriverManagerDataSource 클래스 를 상속받는다는 것이다.

DriverManagerDataSource 클래스

DriverManagerDataSource 클래스는 Spring Framework에서 제공하는 표준 JDBC DataSource인터페이스를 간단히 구현하는 클래스이다. 그런데 해당 클래스의 설명에서 주목해야하는 부분이 있다. 바로 그것은 해당 클래스는 실제 연결 풀링을 하지 않는다는 것이다. 해당 클래스는 직접 데이터에 풀링하는것이 아니지만 다른 모든 호출에 연결한다. (creating new Connections on every call)

2) DB 접근 및 실행

// DB접근 및 실행을 위한 기본 세팅
@Repository
public class JikwonImpl extends JdbcDaoSupport implements JikwonInter{

새로 생성된 클래스에서 JdbcDaoSupport 클래스를 상속받는다. 상속받게 된다면 해당 클래스에서 jdbcDaoSupport의 멤버 메소드와 필드에 접근 할 수 있다.

3) DB세팅 불러오기

@Autowired //DataSource에서 생성한 객체 Bean을 연결
public JikwonImpl(DataSource dataSource) {
	setDataSource(dataSource);
}

처음 세팅한 DB세팅을 불러온다. 이때에 해당 DB세팅은 super class인 JdbcDaoSupport의 멤버인 DataSource에 넣어준다. (Setter method 사용)

그런데 왜 생성자에 @Autowired를 걸었는가?

Spring에서 의존도를 주입하는 방법은 크게 3가지가 있다.

  1. Field Injection
  2. Constructor Injection
  3. Setter Injection
흔히 Field에 선언을 하고 바로 @Autowired 어노테이션을 걸면 Setter와 유사한 기능을 해주기 때문에 매우 편한데 위의 코드에서는 Contructor Injection을 통해 의존도를 주입하고 있다. 그 이유는 작업의 순서 때문인데, 처음 JdbcDaoSupport를 상속받은 JikwonImpl이라는 Class가 호출되면 생성자 부터 호출이 되는데 그때에 superclass인 JdbcDaoSupport의 생성자가 실행이 되고 이후 생성자 호출이 마친 뒤에 Feild Injection이 실행된다. 그런데 JdbcDaoSupport를 실행할 때 이미 DataSource에 대한 정보가 있어야하는데, JdbcDaoSupport의 생성자가 실행되는 시기에는 DataSource에 대한 정보가 없기 때문에 오류가 발생한다.
//3. 의존도 주입
@Autowired
private DataSource dataSource;
setDataSource(dataSource)

public JikwonImpl() { //1. 기본 생성자 실행
		super.JdbcDaoSupport(); //2. super Class의 생성자 먼저 실행
	}

4) RowMapper을 상속받은 내부 Class

class JikwonRow implements RowMapper {
	@Override
    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
	    JikwonDto dto = new JikwonDto(); //DTO
        dto.setJkiwonno(rs.getInt("jikwonno")); //필드명
        dto.setJikwonname(rs.getString("jikwonname")); //필드명
        dto.setBusername(rs.getString("busername")); //필드명
        dto.setJikwonjik(rs.getString("jikwonjik")); //필드명
        return dto;
    }
}

RowMapper 인터페이스는 실행된 Query의 결과가 담긴 ResultSet을 행 단위로 매핑하는 인터페이스이다. 실제 작업순서로는 뒤에 언급할 '5) Query 입력 및 실행' 단계가 선행되지만 해당 기능을 설명하기 위해 순서를 바꿔 설명했다.

5) Query 입력 및 실행

@Override
public List<JikwonDto> getAlljikwon() {
	RowMapper rowMapper = new JikwonRow();
    return getJdbcTemplate().query("SELECT j.jikwonno, j.jikwonname, b.busername, j.jikwonjik "
				+ "FROM jikwon AS j INNER JOIN buser AS b ON j.busernum = b.buserno ", rowMapper);
}

위의 코드를 통해 쿼리를 입력함으로서 결과값을 반환 할 수 있다. 이때에 주목해야할 메소드는 getJdbcTemplate() 이다. 해당 메소드를 이해하기 위해서는 JdbcTemplate 클래스를 먼저 이해해야하는데 해당 클래스는 Jdbc 코어 패키지의 중요 기능을 호출 할 수 있는 클래스이다. 해당 클래스를 통해 수많은 SQL 기능을 실행 할 수 있다.

JdbcTemplate가 가진 다양한 기능중에 우리는 query() 메소드에 주목해 봐야한다. 해당 메소드는 다양한 방법으로 오버로딩 되어있는데 그중 우리가 사용할 방법은 (String sql, RowMapper) 을 인자로 갖는 메소드를 사용할 것이다. 문자열로 SQL query를 입력해주고 뒤에 앞서 언급한 RowMapper 인터페이스를 입력해준다. 그러면 해당 쿼리가 실행되고 해당 쿼리의 결과의 레코드가 소진될때까지 RowMapper 인터페이스 (예시의 경우 상속받은 클래스)가 반복 실행된다.

query() 메소드는 List 콜렉션을 반환값으로 갖는다. 즉 RowMapper를 상속받은 내부 Class에서 리턴한 DTO가 List 콜렉션에 차곡 차곡 쌓이게 된다.

6) 최종

package pack;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

@Repository
public class JikwonImpl extends JdbcDaoSupport implements JikwonInter {

	private DataSource dataSource;

	@Autowired
	public JikwonImpl(DataSource dataSource) {
		setDataSource(dataSource);
	}

	@Override
	public List<JikwonDto> getAlljikwon() {
		RowMapper rowMapper = new JikwonRow();
		return getJdbcTemplate().query("SELECT j.jikwonno, j.jikwonname, b.busername, j.jikwonjik "
				+ "FROM jikwon AS j INNER JOIN buser AS b ON j.busernum = b.buserno ", rowMapper);
	}

	class JikwonRow implements RowMapper {

		@Override
		public Object mapRow(ResultSet rs, int rowNum) throws SQLException {

			JikwonDto dto = new JikwonDto();
			dto.setJkiwonno(rs.getInt("jikwonno"));
			dto.setJikwonname(rs.getString("jikwonname"));
			dto.setBusername(rs.getString("busername"));
			dto.setJikwonjik(rs.getString("jikwonjik"));
			return dto;
		}
	}

}

3. 마무리

  • 처음에는 해당 방법이 너무 익숙하지 않아서 해당 방법을 암기하여 코드를 작성하고 문제를 풀어봤다.
  • 그러나 블로그를 작성하면서 api를 살펴봤고, 다른 개발자분들의 블로그를 살펴보며 개념을 잡게 되었다.
  • Spring으로 넘어오면서 난이도는 Java보다 오른듯 싶지만 그렇기에 이해했을때의 카타르시스는 더욱 배로 찾아오는것 같다.
profile
안녕하세요. 날마다 성장하는 김대현입니다 :)

0개의 댓글