Post

01 Data Access Layer

01 Data Access Layer

1. Data Access Layer

애플리케이션에서 DB와 직접 데이터를 주고받는 모든 기술을 통칭

1. Data Access Layer 종류

범주예시
SQL MapperMyBatis, iBatis 등
ORMHibernate, EclipseLink, JPA 등
단순 JDBCJdbcTemplate, 순수 JDBC
Spring DataSpring Data JPA, Spring Data JDBC 등

2. Data Access Layer 변화

1. JDBC 등장 (1997, Java 1.1)

  • 자바에서 DB와 직접 연결하기 위한 표준 API 등장
  • 특징: SQL 직접 작성, Connection/PreparedStatement/ResultSet 관리 모두 수동
  • 장점: 모든 DB 연동 기술의 기반
  • 단점: 반복 코드 많음, 예외 처리 및 리소스 관리 번거로움

2. JdbcTemplate (2003~ 스프링 초창기)

  • 스프링에서 제공하는 JDBC 편의 라이브러리
  • 특징: Connection, PreparedStatement, ResultSet 관리 자동화
  • 장점: 반복 코드 제거, SQL과 결과 매핑에 집중 가능, 예외 통합 처리
  • 단점: 여전히 SQL 직접 작성 필요

3. ORM (1990년대 후반 ~ 2000년대 초반 등장, Hibernate가 2001년)

  • Hibernate, EclipseLink 등
  • 특징: 객체(Entity) ↔ DB 테이블 자동 매핑, SQL 자동 생성
  • 장점: 객체 중심 개발, SQL 작성 최소화
  • 단점: 복잡한 SQL이나 성능 최적화 필요 시 자동 SQL이 비효율적
  • JPA(2006) 등장: ORM 구현체 표준화

4. SQL 매퍼 (2000년대 초반)

  • 철학: “SQL은 내가 직접 짤게, 대신 실행과 매핑만 도와줘”
  • 특징: SQL 중심 개발, 매핑 자동화
  • 장점: 성능/제어 안정적, 대규모 서비스에 적합
  • 단점: 객체 중심 개발은 제한적

5. Spring Data 계열 (2010년대 이후)

  • Spring Data JPA 등
  • 특징: JPA/Hibernate 위에 추상화 + 편의 기능 제공
  • 장점: Repository 인터페이스만 정의하면 CRUD 가능, 페이징/정렬 지원, 반복 코드 제거
  • 결과: ORM 장점 유지 + 개발 편의성 극대화
  • 비고: SQL 매퍼(MyBatis)도 여전히 사용 가능

2. JdbcTemplate

1. JdbcTemplate

  • 스프링 프레임워크에서 제공하는 JDBC용 편의 라이브러리
  • 반복적인 JDBC 코드(Connection, PreparedStatement, ResultSet 관리 등)를 제거하고, SQL 실행과 결과 매핑에 집중할 수 있게 해주는 객체

2. 목적

  • 반복적인 JDBC boilerplate 코드 제거
  • 개발자가 SQL과 결과 매핑에만 집중하도록 지원
  • 예외 처리 통합 및 리소스 관리 자동화

3. 특징

  • 반복 코드 제거
    • Connection, PreparedStatement, ResultSet 생성과 종료를 자동 처리
    • try-catch-finally 같은 반복적인 JDBC boilerplate 최소화
  • SQL 실행과 매핑 집중
    • 개발자는 SQL과 결과 객체 매핑(RowMapper 등)만 신경 쓰면 됨
    • 반복적인 리소스 관리, 예외 처리 신경 쓸 필요 없음
  • 예외 통합 처리
    • SQLException을 스프링 전용 DataAccessException으로 변환
    • DB 벤더별 예외 차이를 통일시켜서 코드 단순화
  • 다양한 편의 메소드 제공
    • query, queryForObject, update, batchUpdate 등
    • 단일 조회, 리스트 조회, 업데이트, 배치 처리 등 대부분 JDBC 작업 지원
  • 스프링과 통합 용이
    • 트랜잭션, DI(Dependency Injection)과 자연스럽게 결합 가능

3. 소스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Autowired
private JdbcTemplate jdbcTemplate; // jdbcTemplate 주입 받음.

public User findUserById(int id) {
String sql = "SELECT id, name, age FROM users WHERE id = ?";

    return jdbcTemplate.queryForObject( 
        sql,
        new Object[]{id},
        (rs, rowNum) -> new User(
            rs.getInt("id"),
            rs.getString("name"),
            rs.getInt("age")
        )
    );
}

3. ORM

1. ORM

  • 객체 지향 프로그래밍 언어의 객체와 관계형 DB의 테이블을 매핑하는 기술
  • DB 테이블과 자바 클래스(Entity)를 1:1로 연결해서, SQL 없이 객체 중심으로 데이터 처리 가능하게 해줌

    2. 목적

  • 객체와 테이블 간의 데이터 불일치 문제 해결 (Object-Relational Impedance Mismatch)
  • SQL 직접 작성 없이도 CRUD 가능
  • 객체 중심 개발 철학 유지

2. 특징

  • 객체 중심
    • DB 레코드를 자바 객체로 표현
    • SELECT → 객체, INSERT/UPDATE → 객체 상태 반영
  • SQL 자동 생성
    • CRUD, 연관관계(Join) 처리 등을 자동으로 SQL로 변환
  • 연관관계 처리
    • 객체 간 관계(1:1, 1:N, N:M)를 DB FK로 매핑 가능
  • 캐싱 및 성능 최적화
    • 1차 캐시, 지연 로딩(Lazy Loading), Eager Fetch 등 지원

3. 대표 구현체

  • Hibernate: 가장 유명한 자바 ORM
  • EclipseLink, OpenJPA: JPA 표준 구현체
  • JPA (Java Persistence API): ORM을 위한 자바 표준 인터페이스

4. 예시

1. User 엔티티 (User.java)

1
2
3
4
5
6
7
8
9
@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private int age;
    // getter, setter
}

2. UserService (UserService.java)

1
2
3
4
5
6
7
8
9
10
11
@PersistenceContext
private EntityManager entityManager;

@Transactional
public User createUser(String name, int age) {
    User user = new User();
    user.setName(name);
    user.setAge(age);
    entityManager.persist(user);  // 직접 persist 호출
    return user;
}
  • 엔티티 객체 관리 주체
    • @Entity가 붙은 클래스는 JPA/Hibernate가 관리
    • 영속 컨텍스트(Persistence Context) 안에서 객체 상태를 추적
    • persist(), merge(), remove() 등의 메소드로 DB와 동기화
  • 스프링의 역할
    • DI(Dependency Injection): EntityManager, Repository를 스프링이 주입
    • 트랜잭션 관리: @Transactional로 commit/rollback 자동 처리
    • 엔티티가 스프링 빈처럼 관리되진 않지만, 스프링이 JPA/Hibernate 사용 환경을 관리
  • 영속 컨텍스트와 스프링
    • 스프링 컨테이너가 EntityManagerFactory를 관리
    • Repository나 Service 계층에서 엔티티를 사용하면, JPA가 상태를 추적하고 스프링이 트랜잭션을 적용

4. SQL 매퍼

1. SQL 매퍼

  • 개발자가 직접 작성한 SQL을 실행하고, 결과를 자바 객체와 매핑해주는 라이브러리
  • SQL 제어권은 개발자에게 있고, 매핑과 반복 코드를 자동화

2. 목적

  • SQL 작성과 실행을 개발자가 직접 제어하면서도, 결과 매핑과 반복적인 JDBC 처리는 자동화
  • ORM의 자동 SQL이 비효율적일 때 성능/제어를 확보

3. 특징

  • SQL 직접 작성
    • 개발자가 INSERT, UPDATE, SELECT, DELETE SQL을 직접 작성
    • 복잡한 쿼리, JOIN, 서브쿼리 등 제어 가능
  • 자동 매핑
    • SQL 결과(ResultSet)를 자바 객체로 자동 매핑
    • XML Mapper 또는 Annotation 기반 설정 가능
  • 반복 코드 제거
    • JDBC Connection, PreparedStatement, ResultSet 관리 자동 처리
    • try-catch-finally, 리소스 close 불필요
  • 유연한 매개변수 처리
    • 파라미터 바인딩, Map 또는 객체 전달 가능
    • 동적 SQL 작성 지원 (조건별 SQL 분기 가능)
  • 트랜잭션 통합 가능
    • Spring 트랜잭션 관리와 자연스럽게 결합
  • SQL 중심 철학
    • ORM처럼 SQL을 숨기지 않고, 개발자가 원하는 SQL을 그대로 사용
    • 성능 최적화 및 DB 제어권 확보

4. 예시

1. XML

1
2
3
<select id="findUser" parameterType="int" resultType="User">
    SELECT id, name, age FROM users WHERE id = #{id}
</select>

2. JAVA

1
User user = userMapper.findUser(1);

4. Spring Data

1. Spring Data

  • JPA 위 추상화 레이어로, Repository 인터페이스만 정의하면 CRUD, 페이징, 정렬 등을 자동으로 처리해주는 스프링 라이브러리
  • EntityManager를 직접 다루지 않고도 객체 중심 CRUD와 쿼리를 수행 가능

2. 목적

  • 반복적인 CRUD 코드 제거
  • 선언적 트랜잭션과 페이징/정렬 등 편의 기능 제공
  • JPA/Hibernate를 더 쉽게 사용하게 함

3. 특징

특징설명
Repository 기반JpaRepository, CrudRepository 인터페이스 상속만으로 CRUD 메소드 제공
자동 CRUD 구현save(), findById(), findAll(), deleteById() 등 기본 CRUD 자동 처리
커스텀 쿼리메소드 이름으로 쿼리 자동 생성 (findByName, findByAgeGreaterThan), 필요 시 @Query로 JPQL 직접 작성 가능
반복 코드 제거EntityManager 직접 호출 불필요, merge/persist/remove, Optional 처리 등 자동 처리
트랜잭션 통합@Transactional로 commit/rollback 자동 처리, 스프링 트랜잭션과 자연스럽게 결합
페이징/정렬 지원Pageable, Sort 인터페이스만으로 페이징과 정렬 적용 가능
스프링 통합DI, AOP, 트랜잭션 관리 등 스프링 기능 활용 가능

4. 예시

1. Repository

1
2
3
public interface UserRepository extends JpaRepository<User, Long> {
    User findByName(String name);
}

2. Servie

1
2
3
4
5
6
7
8
9
10
@Autowired
private UserRepository userRepository;

User user = new User();
user.setName("홍길동");
user.setAge(20);
userRepository.save(user);

User u = userRepository.findById(1L).orElse(null);
User byName = userRepository.findByName("홍길동");
This post is licensed under CC BY 4.0 by the author.