DAO(Data Acess Object) 패턴

  • 데이터 액세스 계층은 DAO 패턴을 적용하여 비즈니스 로직과 데이터 액세스 로직을 분리하는 것이 원칙이다.
  • 비즈니스 로직이 없거나 단순하면 DAO 와 서비스 계층을 통합 할 수도 있지만, 의미있는 비즈니스 로직을 가진 엔터프라이즈 애플리케이션이라면 데이터 엑세스 계층을 DAO 패턴으로 분리해야 한다.
  • DAO 패턴은 서비스 계층에 영향을 주지 않고 데이터 액세스 기술을 변경할 수 있는 장점을 가지고 있다.

Connection Pooling을 지원하는 DataSource

Connection Pooling은 미리 정해진 개수만큼의 DB Connection 을 Pool 에 준비해두고, 애플리케이션이 요청할 때마다 Pool 에서 꺼내서 하나씩 할당해주고, 다시 돌려받아서 Pool 에 넣는 식의 기법이다.

  • 다중 사용자를 갖는 엔터프라이즈 시스템에서라면 반드시 DB Connection Pooling 기능을 지원하는 DataSource 를 사용해야 한다.
  • Spring 에서는 DataSource 를 공유가능한 Spring Bean 으로 등록해주어 사용할 수 있도록 해준다.

DataSoucre 구현 클래스 종류

  1. 테스트 환경을 위한 DataSource
    • SimpleDriverDataSource
      • Spring 이 제공하는 가장 단순한 DataSource 구현 클래스
      • getConnection() 을 호출할 때 마다, 매번 DB Connection 을 새로 만들고, 따로 pool 을 관리하지 않으므로, 단순한 테스트용으로만 사용해야한다.
    • SingleConnectionDriverDataSource
      • 순차적으로 진행되는 통합 테스트에서는 사용 가능하다.
      • 매번 DB Connection 을 생성하지 않기 때문에, SimpleDriverDataSource 보다 빠르게 동작한다.
  2. 오픈소스 DataSource
    • Apache Commons DBCP
    • c3p0 JDBC / DataSource Resource Pool]
    • 두 가지 모두 setter 메서드를 제공하므로 Spring Bean 으로 등록해서 사용하기 편리하다.

Spring JDBC

JDBC 는 모든 자바의 데이터 액세스 기술의 근간이 된다. Entity Class 와 annotation 을 이용하는 최신 ORM 기술도 내부적으로는 DB 와의 연동을 위해 JDBC 를 이용한다.

  • 안정적이고 유연한 기술이지만, low level 기술로 인식되고 있다.
  • 간단한 SQL 을 실행하는 데도 중복된 코드가 반복적으로 사용되며, DB 에 따라 일관성 없는 정보를 가진 채로 Checked Exception 으로 처리한다.
장점 단점
대부분의 개발자가 잘 알고 있는 친숙한 데이터 액세스 기술로, 별도의 학습 없이 개발이 가능하다. Connection 과 같은 공유 리소스를 제대로 릴리즈 해주지 않으면 시스템의 자원이 바닥나는 버그를 발생시킨다.

Spring JDBC 는 JDBC 의 장점과 단순성을 그대로 유지하면서도 기존 JDBC 의 단점을 극복할 수 있게 해주고, 간결한 형태의 API 사용법을 제공하며, JDBC API 에서 지원되지 않는 편리한 기능을 제공한다.

  • Spring JDBC 는 반복적으로 해야 하는 많은 작업들을 대신 해준다.
  • Spring JDBC 를 사용할 때는 실행할 SQL 과 바인딩 할 파라미터를 넘겨주거나, 쿼리의 실행 결과를 어떤 객체에 넘겨 받을지를 지정하는 것만 하면 된다.
  • Spring JDBC 를 사용하려면 먼저, DB Connection 을 가져오는 DataSource 를 Bean 으로 등록해야한다.

Spring JDBC 가 해주는 작업

  1. Connection 열기와 닫기
    • Connection 과 관련된 모든 작업을 Spring JDBC 가 필요한 시점에서 알아서 진행한다.
    • 진행 중에 예외가 발생했을 때도 열린 모든 Connection 객체를 닫아준다.
  2. Statement 준비와 닫기
    • SQL 정보가 담긴 Statement 또는 PreparedStatement 를 생성하고, 필요한 준비 작업을 해주는 것도 Spring JDBC가 한다.
    • Statement 도 Connection 과 마찬가지로 사용이 끝나고 나면 Spring JDBC 가 알아서 객체를 닫아준다.
  3. Statement 실행
    • SQL 담긴 Statement 를 실행하는 것도 Spring JDBC 가 해준다.
    • Statement 의 실행결과는 다양한 형태로 가져올 수 있다.
  4. ResultSet Loop 처리
    • ResultSet 에 담긴 쿼리 실행 결과가 한 건 이상이면 ResultSet Loop 를 만들어서 반복해주는 것도 Spring JDBC 가 해주는 작업이다.
  5. Exception 처리와 반환
    • JDBC 작업 중 발생하는 모든 예외는 Spring JDBC 예외 변환기가 처리한다.
    • 체크 예외(Checked Exception)인 SQLException 을 런타임 에외(Runtime Exception)인 DataAccessException 타입으로 변환한다.
  6. Transaction 처리
    • Spring JDBC 를 사용하면 transaction 과 관련된 모든 작업에 대해서는 신경 쓰지 않아도 된다. (ex. commit, rollback)

JdbcTemplate 클래스

Spring JDBC 가 제공하는 클래스 중 JdbcTemplate 은 JDBC 의 모든 기능을 최대한 활용할 수 있는 유연성을 제공하는 클래스이다.

  • JdbcTemplate 이 제공하는 기능은 실행, 조회, 배치의 세가지 작업이다.
    • 실행 : Insert 나 Update 같이 DB 의 데이터에 변경이 일어나는 쿼리를 수행하는 작업
    • 조회 : Select 를 이용해 데이터를 조회하는 작업
    • 배치 : 여러 개의 쿼리를 한 번에 수행해야 하는 작업

JdbcTemplate 클래스 생성

  • JdbcTemplate 은 DataSource 를 파라미터로 받아서 아래와 같이 생성할 수 있다.
JdbcTemplate template = new JdbcTemplate(dataSoucrce);
  • DataSource 는 보통 Bean 으로 등록해서 사용하므로 JdbcTemplate 이 필요한 DAO 클래스에서 DataSource Bean 을 DI 받아서 JdbcTemplate 을 생성할 때 인자로 넘겨주면 된다.
  • JdbcTemplate 은 멀티스레드 환경에서도 안전하게 공유해서 쓸 수 있기 때문에 DAO 클래스의 인스턴스 변수에 저장해 두고 사용할 수 있다.

JdbcTemplate 클래스 생성 Code

  • 아래의 코드는 일반적으로 사용되는 DAO 클래스의 기본 구조이다. DataSource 에 대한 수정자 메서드에서 직접 JdbcTemplate 객체를 생성해준다.
public class UserDAOJdbc {
  JdbcTemplate jdbcTemplate;

  @Autowired
  public void setDataSource(Datasource dataSource) {
    jdbcTemplate = new JdbcTemplate(dataSource);
  }
}

JdbcTemplate 클래스의 update() 메서드

  • INSERT, UPDATE, DELETE 와 같은 SQL 을 실행할 때는 JdbcTemplate 의 update() 메서드를 사용한다.
int update(String sql, [SQL 파라미터])
  • update() 메서드를 호출할 때는 SQL 과 함께 바인딩 할 파라미터는 Object 타입 가변인자 (Object ... args) 를 사용할 수 있다.
  • update() 메서드의 리턴되는 값은 SQL 실행으로 영향을 받은 레코드의 개수를 리턴한다. (-1, 0, 1 이 성공, 실패의 기준이 되는 이유)

JdbcTemplate 클래스의 update() 메서드 Code

public int update(User user) {
  StringBuffer updateQuery = new StringBuffer();
  updateQuery.append("UPDATE users SET ");
  updateQuery.append("password=?, name=?");
  updateQuery.append("WHERE id=? ");

  int result = this.jdbcTemplate.update(updateQuery.toString(), user.getName(), user.getPassword(), user.getId()); // StringBuffer 로 만든 SQL 문을 toString() 메서드를 이용
  // 각 값들을 get() 메서드를 통해서 얻어온다.

  return result; // 값을 반환
}

JdbcTemplate 클래스의 queryForObject() 메서드

  • SELECT SQL 을 실행하여 하나의 Row 를 가져올 때는 JdbcTemplate 의 queryForObject() 메서드를 사용한다.
    • queryForObject() 메서드는 여러개의 Column, 하나의 Row
    • query() 메서드는 여러개의 Column, 여러개의 Row
<T> T queryForObject(String sql, [SQL 파라미터], RowMapper<T> rm)
  • SQL 실행 결과는 여러 개의 Column 을 가진 하나의 Row
  • T 는 VO(Value Object) 객체의 타입에 해당된다. (T 는 Colum 이 여러개, Row 가 하나일 때 VO 객체의 타입에 해당된다.)
  • SQL 실행 결과로 돌아온 여러 개의 column 을 가진 한 개의 Row 를 RowMapper 콜백을 이용해 VO 객체로 매핑해준다.

JdbcTemplate 클래스의 queryForObject() 메서드 Code

public User findUser (String id) {
  return this.jdbcTemplate.queryForObejct("SELECT * FROM users WHERE id=?", new Object[] {id}),

  new RowMapper<User>() {
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
      User user = new User();
      user.setId(rs.getString("id"));
      user.setName(rs.getString("name"));
      user.setPassword(rs.getString("password"));

      return user;
        } // RowMapper
      }; // queryForObject
} // findUser

JdbcTemplate 클래스의 query() 메서드

  • SELECT SQL 을 실행하여 여러 개의 Row 를 가져올 때는 JdbcTemplate 의 query() 메서드를 사용한다.
<T> List<T> query(String sql, [SQL 파라미터], RowMapper<T> rm)
  • SQL 실행 결과로 돌아온 여러 개의 column 을 가진 여러 개의 Row 를 RowMapper 콜백을 이용해 VO 객체로 매핑해준다.
  • 결과 값은 매핑한 VO 객체를 포함하고 있는 List 형태로 받는다. (Row 가 여러개이기 때문에) List의 각 요소가 하나의 Row 에 해당한다.

DataSource 설정

  • DataSource 를 Spring Bean 으로 등록하여 사용할 수 있다.

bean.xml

<context:property-placeholder location="classpath:config/value.properties" />

<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
  <property name= "driverClass" value="${db.driverClass}" />
  <property name= "url" value="${db.url}" />
  <property name= "username" value="${db.username}" />
  <property name= "password" value="${db.password}" />
</bean>

value.properties

db.driverClass=oracle.jdbc.OracleDriver
#mysql, mariadb 의 경우에는 다른 driverClass 와 다른 url 을 사용해야한다.
db.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
db.username=scott
db.password=tiger

'Java, Spring > 개념정리' 카테고리의 다른 글

DispatcherServlet  (0) 2023.02.02
스프링 프레임워크(Spring Framework)  (0) 2023.01.17
AOP(Aspect Oriented Programming)  (0) 2023.01.12
DI Container  (0) 2023.01.12
DI(Dependency Injection)  (0) 2023.01.12

+ Recent posts