01. Java Persistence API 소개

zwundzwzig·2023년 2월 2일
0
post-thumbnail

1.1 SQL을 직접 다룰 때 발생하는 문제

웹 어플리캐이션에서 RDBMS를 사용해 데이터를 관리하려면 SQL을 다뤄야 한다. 그 언어가 자바라면, JDBC API를 사용할 때 SQL을 작성하는데 많은 시간을 할애해야 한다.

비록 이후 발전한 MyBatis나 JdbcTemplate와 같은 SQL 매퍼를 통해 코드량을 줄일 수 있지만 여전히 SQL 의존적인 개발을 할 수밖에 없다.

1.1.1 반복 그리고 또 반복

자바와 RDBMS가 직접 연동된 코드를 작성한다면, 다음과 같다. 참고로 Id, name을 컬럼으로 갖는 Member 테이블이 있다고 가정하자.

public class MemberDAO {

  private final DataSource dataSource;

  public JdbcMemberRepository(DataSource dataSource) {
    this.dataSource = dataSource;
  }
  
  private Connection getConnection() {
    return DataSourceUtils.getConnection(dataSource);
  }

  public Member signup(Member member) {
    String sql = "INSERT INTO member(name) VALUES(?)";

    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;

    try {
      conn = getConnection();
      pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
      pstmt.setString(1, member.getName());
      pstmt.executeUpdate();
      rs = pstmt.getGeneratedKeys();

      if(rs.next()) member.setId(rs.getLong(1));
      else throw new SQLException("id 조회 실패");
      
      return member;
    }
    catch (SQLException e) {
      throw new IllegalStateException(e);
    }
    finally {
      close(conn, pstmt, rs);
    }

  }

  private void close(Connection conn, PreparedStatement pstmt, ResultSet rs) {
    try {
      if(rs != null) rs.close();
    } 
    catch (SQLException e) {
      e.printStackTrace();
    }
    
    try {
      if(pstmt != null) pstmt.close();
    } 
    catch (SQLException e) {
      e.printStackTrace();
    }
    
    try {
      if(conn != null) conn.close();
    } 
    catch (SQLException e) {
      e.printStackTrace();
    }
  }
  
  private void close(Connection conn) throws SQLException {
    DataSourceUtils.releaseConnection(conn, dataSource);
  }

  }

위와 같은 방대한 방식은 너무 많은 SQL과 JDBC API를 코드로 작성해야 하고, 이는 불필요한 반복 작업만 야기해 개발자의 성장에 하등 도움이 안 될 것이다.

1.1.2 SQL 의존적인 개발

만약 Member 테이블의 컬럼이 추가된다면 어떻게 될까?

  • 우선 Member Entity에서 멤버 변수를 하나 추가하고,
  • SQL문도 수정하고,
  • pstmt에 set.. 메소드로 추가로 매핑하고,

이런 불필요한 작업을 계속 반복해야 할 것이다.

이렇게 데이터에서 변동이 생기면, 데이터 접근 계층(DAO)을 사용해 SQL을 숨겨도 결과적으로 엔티티에 대한 신뢰도가 떨어지고, 진정한 의미의 계층 분할이 이뤄지지 않는 문제가 생긴다.

결과적으로 SQL 의존적인 개발을 피할 수 없게 된다.

1.1.3 JPA와 함께 라면?

그래서, 지금 내가 이 글을 쓰고 있다.

JPA가 제공하는 메소드로 간편하게 CRUD는 물론 낮은 의존성으로 데이터를 관리할 수 있다.

이러한 최신 기술 JPA를 공부해서 멋진 스프링개발자가 되자.

1.2 패러다임의 불일치

자바는 대표적인 객체지향언어이다. 하지만, RDBMS는 데이터 중심으로 구조화되어 있고 집합적인 사고를 요구한다. 객체지향과 완전히 지향점이 다른 것이다.

그래서 개발자가 중간에서 해결해야 하지만 두 패러다임 불일치 문제를 해결하는데 너무 많은 시간과 코드를 소비한다. 그러한 문제를 구체적으로 보고 JPA를 통한 해결책도 알아보자.

1.2.1 상속

객체의 상속 관계와 유사한 모델이 RDBMS의 슈퍼타입-서브타입 관계이다. 자바 코드로는 추상 클래스인 ITEM을 상속하는 각각의 객체를 만들 수 있을 것이다.

만약 JDBC API만으로 Album 객체를 저장한다면, 객체를 분해해서 ITEM과 ALBUM 테이블에 각각 INSERT문으로 데이터를 넣어줘야 할 것이다.

이건 너무 비효율적이다!

JPA와 함께라면? 개발자는 그저 자바 컬렉션에 객체를 저장하듯 JPA에게 객체를 저장하면 된다. 이때 persist로 삽입, find 메서드로 조회가 가능하다.

1.2.2 연관관계

객체는 참조를 통해서, DB는 외래 키를 사용해 연관 관계를 맺는다.

여기서 나타나는 패러다임 불일치는,

  • 객체는 참조가 있는 방향으로만 조회가 가능하다.
  • 반면 테이블은 외래 키 하나로 연관된 테이블 간 조회가 가능핟.

만약 객체의 멤버 변수를 테이블에 맞춰 타입을 지정하면 객체지향의 특징을 잃기 쉽다.

그래서 참조를 보관하는 방식으로 모델링하면 객체지향으로 가능하다.

class Member {
	String id;
    Team team; // Long teamId 가 아닌, 참조로 연관관계를 맺는다.
    String username;
}

class Team {
	Long id;
    String name;
}

JPA를 사용한다면? 역시 몇 가지 메소드로 간단하게 패러다임 불일치 문제를 해결할 수 있다.

1.2.3 객체 그래프 탐색

객체 그래프 탐색을 통해 참조에 참조로 여러 객체를 탐색할 수 있다. 하지만, SQL에선 선언문에 따라 탐색 범위가 제한된다. 결국 DAO를 열어서 하나하나 SQL을 직접 확인해야 할 것이다. 이는 패러다임 불일치를 야기한다.

JPA를 사용한다면? 연관된 객체를 사용하는 시점에 적절한 조회문을 실행한다.

이 기능은 실제 객체를 사용하는 시점까지 DB 조회를 미룬다고 해서 지연 로딩이라고 한다. JPA는 지연로딩을 투명하게 처리한다.

1.2.4 비교

DB는 기본 키의 값으로 각 row를 구분한다. 반면 객체는 동일성==과 동등성equals()으로 비교한다.

이런 패러다임의 불일치 문제를 위해 같은 로우를 조회할 때마다 같은 인스턴스를 반환하도록 구현하는 건 쉽지 않다. 여기에 트렌젝션이 동시에 실행되면 더 어려워 진다.

JPA를 사용한다면? 한 트렌젝션 내 같은 객체가 조회되는 것을 보장한다.

1.3 JPA란 무엇인가?

EJB 3.0가 hibernate 기반으로 만든 새로운 자바 진영의 Object-Relational-Mapping 기술 표준.

jpa.persist(member) : 저장

jpa.find(memberId) : 조회

JPA 표준 인터페이스와 구현체

JPA는 자바 ORM 기술에 대한 API 표준 명세서이다.

JPA를 사용해야 하는 이유

1. 자바 컬렉션에 객체를 저장하듯 사용해 생산성이 높다.

2. SQL 의존적 개발에서 벗어나 코드량이 줄고 패러다임 불일치를 해결해줘 유지보수가 용이하다.

출처

3. 데이터 접근 추상화할 수 있고, RDBMS 벤더에 종속되지 않아 독립적으로 사용 가능하다.

JPA는 러닝커브가 높은 개념이다. 객체지향과 관계형 데이터베이스 개념을 포괄하고 있기 때문이다! 그래도 멋진 개발자가 되기 위해 잘 공부해보자!

🧷 참조 교재

  • 김영한, 『자바 ORM 표준 JPA 프로그래밍』 에이콘(2015)
profile
개발이란?

0개의 댓글