[자바/스프링] 데이터 액세스 계층

데이터베이스 접근을 위해 필요한 사항

  1. 데이터베이스 드라이버 클래스를 클래스패스에 위치 시킴
  2. SQL 문 실행
    • JDBC 사용
      1. 데이터베이스 커넥션(Connection) 객체를 반환하는 데이터소스(DataSource) 인터페이스 구현 객체 생성
      2. 데이터베이스 연결 관리를 위한 커넥션 객체 생성
      3. 커넥션 객체의 prepareStatement() 메서드에 SQL 문 인자로 전달
      4. 매개변수를 prepareStatement() 메서드가 반환하는 PrepareStatement 객체에 바인딩 (파라미터 바인딩)
        • PrepareStatement 객체: 사전 컴파일된 SQL 문이 저장되어 있는 객체
      5. PrepareStatement 객체의 SQL 문 실행 메서드 호출
      6. SQLException 처리
      7. 메모리 누수를 막기 위해 Connection, PrepareStatement, ResultSet 객체의 데이터베이스 및 JDBC 리소스를 직접 해제
    • JdbcTemplate 사용
    • JPA 사용
      1. 엔티티 클래스(퍼시스턴스 클래스) 정의 및 디폴트 생성자 정의
      2. 엔티티 매니저 팩토리(EntityManagerFactory) 객체로부터 엔티티 매니저(EntityManager) 객체 생성
    • 하이버네이트 사용
      1. 엔티티 클래스(퍼시스턴스 클래스) 정의
      2. 세션 팩토리(SessionFactory) 객체로부터 세션(Session) 객체 생성
    • Spring Data JPA 사용

관심사의 분리를 적용한 데이터베이스 접근

  • 데이터베이스에 접근하여 데이터 처리하는 역할을 수행하는 애플리케이션 계층(퍼시스턴스 계층)을 위한 클래스를 별도로 분리 -> DAO 클래스
    • 데이터 액세스 로직 캡슐화 및 추상화
  • DAO 클래스의 관심사: 데이터베이스에 접근하여 SQL 문 실행을 통해 데이터 처리를 수행하며 이 과정 중 발생하는 예외를 처리하는 것
    • JDBC 사용
      1. 데이터베이스 연결: Connection 객체 사용
      2. SQL 문 실행: PrepareStatement 객체 사용
      3. 데이터베이스 연결 해제: Connection, PrepareStatement, ResultSet 객체의 close() 메서드 호출
      4. 데이터 액세스 로직 실행 중 발생 가능한 예외 처리: SQLException 예외 처리
    • JdbcTemplate 사용
    • JPA 사용
    • Spring Data JPA 사용

DAO 클래스의 관심사 및 책임 분리와 기술 종속성 제거

  1. 데이터베이스 접근 및 SQL 문 처리 코드 추상화 (데이터베이스 기술 종속성 제거)
    • 방법: JDBC를 사용하거나 ORM 프레임워크를 사용하여 데이터베이스에 종속적이지 않는 DAO 클래스 작성
    • 장점: 데이터베이스 기술 교체 용이
  2. 교체 가능한 DAO 클래스 정의 (퍼시스턴스 계층 종속성 제거)
    • 방법: 인터페이스를 구현하도록 함으로써 코드 수정 없이 인터페이스 구현 객체 간 교체가 가능하도록 함
    • 장점: DAO 기술 교체 용이
  3. 데이터베이스에 종속적인 예외 발생을 공통적인 예외로 변환 (데이터베이스 예외 종속성 제거)
    • 방법: 반드시 예외를 잡아 처리해야 하는 체크 예외(checked exception)인 SQLException이 발생하면 예외를 잡아 처리하지 않아도 되는 언체크 예외(unchecked exception)인 RuntimeException 상속 예외 클래스로 감싸서 전달
    • 장점: 특정 데이터베이스에 종속적인 SQLException을 데이터베이스 및 예외 원인의 종류 별로 에러 코드를 매핑하여 RuntimeException으로 변환함으로써 예외의 원인을 보다 명확하게 파악할 수 있게 함
  4. 트랜잭션 관리 추상화 (트랜잭션 기술 종속성 제거)
    • 방법: 스프링이 제공하는 트랜잭션 추상화를 사용하여 특정 트랜잭션 처리 환경 및 기술에 종속적이지 않는 트랜잭션 처리(트랜잭션 경계 설정) 코드 작성
    • 장점
      • 트랜잭션을 제공하는 서비스 적용 환경 교체(로컬 및 분산 트랜잭션 간 변경, ORM 교체 등) 용이
      • DAO 기술이 교체되더라도 DAO 클래스에 트랜잭션 처리를 위한 코드 수정이 최소화되어 의존성 주입된 트랜잭션 관리자 객체만 교체하면 됨

트랜잭션 적용

  • 트랜잭션 경계 설정은 서비스(비즈니스) 계층에서 수행해야 하므로 Connection 객체 생성 및 사용도 서비스 계층에서 일어나야 함
  • Connection 객체는 스레드 안전해야 함
    • 스레드 별로 Connection 객체를 생성하고 서로 공유하지 않도록 하여 스레드의 작업과 트랜잭션 경계 설정이 서로 독립적으로 진행되어야 함
  • 서비스 계층과 퍼시스턴스 계층간 DAO 기술 종속성을 없애고 DAO 기술 교체를 쉽게 하기 위해 서비스 클래스에서 생성한 Connection 객체를 DAO 클래스에 직접 전달하지 않아야 함
  • 위와 같은 조건을 모두 만족하기 위해 스프링이 제공하는 트랜잭션 동기화 기능을 사용함으로써 서비스 계층의 트랜잭션 시작 및 종료를 위한 Connection 객체를 별도로 저장하여 공유하도록 할 수 있음
  • 두 개 이상의 데이터베이스 연결이 필요하거나 기타 트랜잭션을 지원하는 서비스의 연결이 추가적으로 필요한 경우 분산(글로벌) 트랜잭션 관리가 필요하며 이를 위해서는 JTA(Java Transaction API)가 제공하는 트랜잭션 관리자를 사용하여 분산 트랜잭션에 대한 관리가 필요함
  • ORM 프레임워크를 사용하는 경우 해당 프레임워크를 위한 별도의 트랜잭션 관리자 구현 객체 사용이 필요하므로 DAO 기술 교체에 따른 트랜잭션 처리 방법에 종속성이 남아 있음
  • 트랜잭션 관리 추상화를 위해서는 스프링이 제공하는 트랜잭션 서비스 추상화 기술을 사용하면 됨
    • 스프링은 트랜잭션 추상화를 위해 PlatformTransactionManager라는 인터페이스를 제공함
    • 로컬 및 분산 트랜잭션, JDBC 및 ORM 프레임워크 모두에 대해 공통적으로 트랜잭션 관리자는 PlatformTransactionManager 인터페이스의 구현 객체이므로 서비스 계층에 해당 인터페이스 구현 객체를 주입하기만 하면 됨
      • JDBC의 로컬 트랜잭션 사용: DataSourceTransactionManager 구현체 사용
      • JTA의 분산(글로벌) 트랜잭션 사용: JTATransactionManager 사용
      • JPA 사용: JPATransactionManager
      • 하이버네이트 사용: HibernateTransactionManager
  • 서비스 계층에서 PlatformTransactionManager 인터페이스의 구현 객체를 의존성 주입 받아 사용함
  • PlatformTransactionManager 인터페이스의 구현 객체는 스레드 안전하므로 멀티 스레드 환경에서 트랜잭션 관리자를 스프링의 빈으로 등록하여 싱글톤으로 사용 가능
  • 스프링의 트랜잭션 추상화로 인해 서비스 계층은 트랜잭션 관리에 대한 책임을 더 이상 갖지 않게 되며 비즈니스 로직에만 관심이 있게 됨

Comments