본문 바로가기

더 나은 엔지니어가 되기 위해/지금은 안쓰는 자바

[부스트코스 웹 프로그래밍] 스프링 JDBC

부스트코스 웹 프로그래밍 BE 영상을 보며 공부한 것을 간단히 정리한다.

1. Spring JDBC

이전에 쓰던 JDBC 를 그대로 갖다쓰면, 반복적인 코드가 많아서 전체적으로 코드가 매우 지저분해짐.
Spring JDBC는 이러한 반복작업을 대신해주어, 사용자가 처리해야할 부분을 간소화 시킴.

1) 개발자가 해야할 일은?

원래 JDBC 설정 프로세스 중, 볼드친 부분만 개발자가 작성하고 나머지는 스프링 프레임워크가 알아서 해줌.

  1. 연결 파라미터 정의
  2. 연결 오픈
  3. SQL 문 지정
  4. 파라미터 선언과 파라미터 값 제공
  5. Statement 준비와 실행
  6. 결과를 반복하는 루프 설정
  7. 각 이터레이션에대한 작업 수행
  8. 모든 예외 처리
  9. 트랜잭션 제어
  10. 연결, Statement, resultset 닫기

2) DTO, DAO, ConnetionPool, DataSource

  • DTO (Data Transfer Object)
    • 계층간 데이터 교환을 위한 자바빈즈
    • 로직 없이, 데이터만을 담고있는 객체
    • 필드와 Getter, Setter 및 Object 메쏘드만을 가진다.
  • DAO (Data Access Object)
    • 데이터를 조회하는 기능을하는 객체
    • 보통 데이터베이스에 접근하는 객체임
  • ConnectionPool
    • DB 와 항시 연결되어있는 객체들
    • DB 와의 연결이 필요하면 이 객체를 갖다쓰고 반납하면 됨.
    • DataSource 에 의해 제어.
  • DataSource
    • ConnectionPool 을 관리하는 객체
    • ConnectionPool 을 이용해 연결, 반납하는 작업 수행

2. Spring JDBC 사용

1) pom.xml 에서 dependency 추가

기존에 스프링 프레임워크가 추가되어있는 상태에서 다음 artifact 들을 추가.
외부에는 mysql 서버가 돌고있음.

<!--pom.xml-->

...
<dependencies>
  ...
  <!--spring-jdbc 관련-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
   </dependency>

  <!--spring-transaction 관련-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${spring.version}</version>
  </dependency>

  <!--java와 mysql 연동 관련-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.45</version>
  </dependency>
  ...
</dependencies>
...

2) Config 설정과 추가

DB 와 연동할 설정파일을 세팅한다.

// DBConfig.java

package kr.or.connect.daoexam.config;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class DBConfig {
  private String driverClassName = "com.mysql.jdbc.Driver";
  private String url = "jdbc:mysql://localhost:3306/connectdb?useUnicode=true&characterEncoding=utf8";

  private String username = "connectuser";
  private String password = "connect123!@#";

  // 실제로 DB와 연동되는 객체는 dataSource. 
  // dataSource는 내부적으로 ConnectionPool 을 이용하여 제어.
  @Bean
  public DataSource dataSource() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(driverClassName);
    dataSource.setUrl(url);
    dataSource.setUsername(username);
    dataSource.setPassword(password);
    return dataSource;
  }
}

이렇게 설정한 DBConfig 클래스를 ApplicationConfig 에 등록

// ApplicationConfig.java

package kr.or.connect.daoexam.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({DBConfig.class}) // 여기만 추가!
public class ApplicationConfig {

}

3) DB Entity(Dto) 객체 작성

실제 DB 에서 설계된 Entity 를 객체 양식으로 구현한다.
필드, Getter, Setter 만 있으면 됨.
사실상 여기선 Dto 에 해당.

// Role.java

package kr.or.connect.daoexam.dto;

public class Role {
  private int roleId;
  private String description;

  // Getter, Setter (생략)
  ...
}

4) DaoSql, Dao 객체 작성

DaoSql 에는 해당 객체에 관한 쿼리문을 변수에 미리 선언해놓음.
즉 한 번 변수에 선언 해놓으면, 추후 직접 쿼리문을 작성안하고 변수만 불러다 쓰면 됨.

// RoleDaoSqls.java

package kr.or.connect.daoexam.dao;

public class RoleDaoSqls {
  public static final String SELECT_ALL = "SELECT role_id, description FROM role order by role_id";
}

Dao는 해당 객체에 관한 DB 테이블에 접근하고 원하는 기능을 수행하고 반환하는 역할을 함.

// RoleDao.java

package kr.or.connect.daoexam.dao;

import static com.examples.sample2.dao.RoleDaoSqls.*; 
// RoleDaoSqls 에 있는 SELECT_ALL 을 바로 사용 가능
...

@Repository
public class RoleDao {
  private NamedParameterJdbcTemplate jdbc;
  private SimpleJdbcInsert insertAction;
  private RowMapper<Role> rowMapper = BeanPropertyRowMapper.newInstance(Role.class);
  // DBMS 와 Java class 의 이름 규칙을 맞춰줌

    public RoleDao(DataSource dataSource) {
    // 객체 생성시, dataSource를 받아 Spring JDBC template 에 전달
    this.jdbc = new NamedParameterJdbcTemplate(dataSource);
    this.insertAction = new SimpleJdbcInsert(dataSource)
                .withTableName("role");
    }

    public List<Role> selectAll(){
    // jdbc.query는 결과물(dto)을 List 로 담아 반환.
    return jdbc.query(SELECT_ALL, 
                      Collections.emptyMap(), // SQL 에 바인딩할 값이 있을 때, 전달 
                      rowMapper); // SELECT 결과를 DTO 에 담음.
    }

}

이렇게 만든 dao 도 Beans 로 사용할 수 있게, Configuration 에 등록해줘야 함.

// ApplicationConfig.java

...
@ComponentScan(basePackages = { "kr.or.connect.daoexam.dao" })
public class ApplicationConfig {
}

5) 사용하기

이제 사용하는 법만 남았는데, DI 컨테이너로부터 Dao Bean 을 받아 사용하면 된다.

// SelectAllTest.java

package kr.or.connect.daoexam.main;

...

public class SelectAllTest {

  public static void main(String[] args) {
    ApplicationContext ac = new AnnotationConfigApplicationContext(
      ApplicationConfig.class); 

    // Dao Bean 받아냄.
    RoleDao roleDao = ac.getBean(RoleDao.class);

    // 아이템 전체 조회 후 출력
    List<Role> list = roleDao.selectAll();

    for(Role role: list) {
      System.out.println(role);
    }
  }
}