JPA-01 개요

yj k·2023년 4월 6일
0

jpa

목록 보기
1/14

JPA(Java Persistence API) 영속성 프레임워크

ORM(Object Relational Mapping) : 객체관계 매핑
JPA :

  • ORM을 자바 언어로 작성하는 기술
  • 마이바티스에서는 SQL구문 작성후 매핑 설정을 해주었다면
    JPA에서는 설정을 해주면 SQL구문도 자동 생성.
  • DBMS별로 dialect를 제공한다.(자동으로 생성된 SQL구문을 mySQL, Oracle 간 변경도 자동으로 해준다.)

JPA 사용 이유

JDBC의 문제점

  1. 애플리케이션과 데이터베이스 중간에서 SQL과 JDBC API 사이에서 데이터를 변환해주는 작업을 개발자가 직접 해주어야 한다.
    너무 많은 코드를 작성해야 하고, 반복되는 코드를 계속 사용해야 하는 문제점이 있다.

조회한 데이터를 자바 객체로 개발자가 직접 변환을 해 주어야 한다.

이런 작업들은 마이바티스를 통해서 해결이 가능하다.

List<Menu> menuList = new ArrayList<>();
        while(rset.next()) {
            Menu menu = new Menu();
            menu.setMenuCode(rset.getInt("MENU_CODE"));
            menu.setMenuName(rset.getString("MENU_NAME"));
            menu.setMenuPrice(rset.getInt("MENU_PRICE"));
            menu.setCategoryCode(rset.getInt("CATEGORY_CODE"));
            menu.setOrderableStatus(rset.getString("ORDERABLE_STATUS"));

            menuList.add(menu);
        }
  1. SQL에 의존적인 개발을 하게 된다.
    이는 요구사항의 변경에 따라 애플리케이션의 수정이 SQL의 수정으로도 이어져야 하며, 이러한 수정 영향을 미치는 현상은 오류를 발생시킬 가능성도 있지만 유지보수성에도 악영향을 미친다.
    또한 객체를 사용할 때 SQL에 의존하게 되면 객체에 값이 무엇이 들어있는지 확인해보기 위해 SQL을 매번 살펴봐야 한다.

2-2. 연관된 객체 문제
메뉴에 해당하는 카테고리의 이름을 함께 조회해야 한다는 요구사항이 변경되었다.

JPA는 데이터베이스에 저장하고 사용할 때 개발자가 직접 SQL문을 작성하지 않는다.
JPA가 제공하는 API를 사용하면 내부에서 SQL을 생성해서 동작을 시킨다.
따라서 SQL에 의존적이지 않게 된다. (의존하는 것은 직접 사용하지 않으면 의존성이 낮아지게 된다.)
또한 JPA를 사용하여 연관관계 객체를 매핑 설정 해두면 항시 연관된 객체도 함께 조회하기 때문에 사용하는 측에서 신뢰하고 사용할 수 있다.(NPE 발생하지 않음을 신뢰할 수 있음)

  1. 패러다임 불일치의 문제가 발생할 수 있다.
    관계형 데이터 베이스는 데이터 중심으로 구조화 되어 있고, 집합적인 사고를 요구한다.
    그리고 객체지향에서 이야기하는 추상화, 상속, 다형성 같은 개념이 존재하지 않는다.
    지향하는 목적 자체가 다르기 때문에 이를 표현하는 방법이 다르고, 그렇기 때문에 객체 구조를 테이블 구조에 저장하는데 한계가 있다.
    이런 객체과 관계형 데이터베이스 사이에 패러다임 불일치 문제를 해결하는데 너무 많은 시간과 코드가 소비된다.

3-1. 상속 문제
객체지향언어의 상속 개념과 유사한 것이 데이터베이스의 서브타입엔터티 이다.
유사한 것 같지만 다른 부분은 데이터베이스의 상속은 상속 개념을 데이터로 추상화 하여 슈퍼타입과 서브타입으로 구분하고,
슈퍼타입의 모든 속성들을 서브타입이 공유하지 못하며 물리적으로도 다른 테이블로 분리가 된 형태이다. (설계에 따라 속성으로 추가되기도 함)
두 개 서로 다른 테이블을 조회하기 위해서는 공유하는(FK) 컬럼을 이용해 JOIN을 해서 사용해야 한다.
하지만 객체지향의 상속은 슈퍼타입의 속성을 공유해서 사용하기 때문에 여기서 패러다임 불일치 현상이 발생하게 된다.
또한 insert 시에는 각 테이블에 insert구문을 따로따로 실행시켜야 한다.

JPA는 상속과 관련된 패러다임의 불일치 문제를 개발자 대신에 해결해준다.
마치 컬렉션에 객체를 저장하듯 JPA에게 객체만 저장하면 된다.

3-2. 연관관계
객체지향에서 말하는 가지고 있는(assosication 연관 관계, 혹은 collection 연관 관계)경우 데이터베이스의 저장 구조와는 다른 형태이다.
따라서 이러한 패러다임 불일치 현상을 없애기 위한 개발자의 많은 노력이 필요하게 된다.
즉, 조인한 컬럼값들을 맞는 객체의 속성에 값을 대입하고 연관관계에 있는 객체도 속성으로 넣어주어야 한다.
만약 이러한 관계설정이 누락되는 경우 NPE가 발생할 가능성이 생기게 된다.

Menu menu = new Menu();
    Category category = new Category();
    
    menu.setCategory(category);       //메뉴와 카테고리의 관계 설정.

하지만 JPA에서는 정말 간단하게 이 문제가 해결된다.

Menu menu = entityManager.find(Menu.class, menuCode);
    Category category = menu.getCategory();
    //연관객체를 함께 조인해서 조회하는 것이 보장된다. (NPE 발생하지 않음)
    

3-3. 객체 그래프 탐색
위와 같이 연관관계가 연이어서 여러 개의 객체간의 복잡한 관계가 형성이 된 경우에는 그 문제가 더 발생할 가능성이 커진다.
이게 NPE 발생하는지 확인하기 위해서는 SQL부터 확인해야 하고 JDBC API 코드의 데이터 변환 부분도 살펴봐야 한다.

하지만 JPA에서는 같은 방식으로 사용하더라도 category객체가 반드시 있음을 보장한다.
즉, 연관관계의 객체를 신뢰하고 마음껏 객체 그래프를 탐색하며 조회할 수 있다.

  1. 동일성 보장
    객체의 비교는 동일성 비교와 동등성 비교라는 두 가지 방법으로 구분이 된다.
    JDBC를 이용하여 조회한 두 개의 Menu객체는 동일한 로우를 조회하더라도 같은 값을 가지는 동등성을 가지지만 동일성을 가지지는 않는다.
    반면 JPA를 이용하여 조회한 두 개의 Menu객체는 동일한 로우를 조회하는 경우 동일성을 보장하게 된다. (단순 == 비교 가능해짐)
    데이터베이스르 로우는 인스턴스이다. 즉, 인스턴스는 몇 번 조회해도 동일성을 가져야 한다.
    동등성을 가지는 객체를 동일성을 가지게 하기 위해 equals()와 hashcode()를 재정의 해서 사용할 수 있다.

같은 값을 가지지만(동등성 o) 서로 다른 주소를 가진다(동일성 x)

assertFalse(menu1 == menu2);
        assertEquals(menu1.getMenuName(), menu2.getMenuName());

        System.out.println("menu1 = " + menu1);
        System.out.println("menu2 = " + menu2);

하지만 JPA로 구현하는 경우 동일 비교가 가능해진다.

Menu menu1 = entityManager.find(Menu.class, 12);
    Menu menu2 = entityManager.find(Menu.class, 12);
    
    menu1 == menu2;    //true

0개의 댓글