JPA

[JPA] JPA의 장단점

yemong 2026. 3. 15. 21:51
JPA(Java Persistence API)이란?
JPA는 자바에서 객체와 관계형 데이터베이스를 매핑하기 위한
ORM(Object Relational Mapping) 기술의 표준 인터페이스이다.
개발자가 SQL 중심이 아니라 객체 중심으로 데이터를 다룰 수 있도록 도와준다.


JPA의 장점

1. 개발자가 직접 SQL을 작성하지 않아도 자동으로 SQL문을 생성해 주어 생산성이 높아진다.

JDBC를 직접 이용해서 쿼리를 작성한다면 다음 코드와 같다.

@DisplayName("연관된 객체 문제 확인")
    @Test
    void testAssociationObject() throws SQLException {

        // given
        String query = "SELECT A.MENU_CODE, A.MENU_NAME, A.MENU_PRICE, B.CATEGORY_CODE, "
                + "B.CATEGORY_NAME, A.ORDERABLE_STATUS "
                + "FROM TBL_MENU A "
                + "JOIN TBL_CATEGORY B ON (A.CATEGORY_CODE = B.CATEGORY_CODE)";
        // when
        Statement stmt = con.createStatement();
        ResultSet rset = stmt.executeQuery(query);

        List<MenuAndCategory> menuAndCategories = new ArrayList<>();
        while (rset.next()) {
            MenuAndCategory menuAndCategory = new MenuAndCategory();
            menuAndCategory.setMenuCode(rset.getInt("MENU_CODE"));
            menuAndCategory.setMenuName(rset.getString("MENU_NAME"));
            menuAndCategory.setMenuPrice(rset.getInt("MENU_PRICE"));
            menuAndCategory.setCategory(new Category(rset.getInt("CATEGORY_CODE"),
                    rset.getString("CATEGORY_NAME")));
            menuAndCategory.setOrderableStatus(rset.getString("ORDERABLE_STATUS"));
        }

        // then
        Assertions.assertTrue(!menuAndCategories.isEmpty());
        menuAndCategories.forEach(System.out::println);

        rset.close();
        stmt.close();
    }

query와 DB 에 맞춰서 자바코드를 작성하면 일일이 코드를 작성해야 하며, 쿼리가 변경되었을 때 연쇄적으로 변경되어야 하는 코드가 발생한다.

JPA를 이용하는 경우, SQL을 수정할 필요가 없으므로 필드 변경시 SQL이 자동으로 수정되어 유지보수가 향상된다.

 

2.  캐시를 활용한 성능 최적화로 인해 트랜잭션을 처리하는 시간이 단축된다.

JPA는 영속성 컨텍스트의 1차 캐시를 통해 같은 트랜잭션 내에서 엔티티의 동일성을 보장한다.

    @DisplayName("조회한 두개의 행을 담은 객체의 동일성 비교 테스트")
    @Test
    void testEquals() throws SQLException {

        // given
        String query = "SELECT MENU_CODE, MENU_NAME FROM TBL_MENU WHERE MENU_CODE = 12";

        // when
        Statement stmt1 = con.createStatement();
        ResultSet rset1 = stmt1.executeQuery(query);

        Menu menu1 = null;
        while (rset1.next()) {
            menu1 = new Menu();
            menu1.setMenuCode(rset1.getInt("MENU_CODE"));
            menu1.setMenuName(rset1.getString("MENU_NAME"));
        }

        Statement stmt2 = con.createStatement();
        ResultSet rset2 = stmt2.executeQuery(query);

        Menu menu2 = null;
        while (rset2.next()) {
            menu2 = new Menu();
            menu2.setMenuCode(rset2.getInt("MENU_CODE"));
            menu2.setMenuName(rset2.getString("MENU_NAME"));
        }

        // then
        Assertions.assertNotEquals(menu1, menu2);
    }
        /* 설명
        * JDBC에서는 동일한 쿼리를 여러 번 실행하면 매번 새로운 객체가 생성된다.
        * 따라서 같은 데이터를 조회하더라도 서로 다른 객체가 되어 동일성이 보장되지 않는다.
        *
        * 반면 JPA는 영속성 컨텍스트(1차 캐시)를 사용한다.
        * 동일한 엔티티를 조회하면 영속성 컨텍스트에 저장된 객체를 반환하기 때문에
        * 같은 트랜잭션 내에서는 객체 동일성이 보장된다.
        *
        * Menu menu1 = entityManager.find(Menu.class, 1);
        * Menu menu2 = entityManager.find(Menu.class, 1);
        *
        * 위 경우 menu1 == menu2 가 된다.
        */
}

같은 행을 조회하더라도 JDBC에서는 매번 새로운 객체가 생성되기 때문에 자바에서는 서로 다른 객체가 된다.
이러한 객체와 데이터베이스 사이의 불일치를 해결하기 위해 JPA를 사용하며, JPA는 PK 값을 기준으로 엔티티를 관리한다.
따라서 같은 트랜잭션 내에서 동일한 엔티티를 조회하면 영속성 컨텍스트에 저장된 객체를 반환하여 객체의 동일성을 보장한다.

JPA의 단점

1. 너무 복잡한 SQL문은 표현하기 어렵다.

- 복잡한 SQL(서브쿼리, 윈도우 함수, 복잡한 조인 등) 을 작성하기 어렵거나 가독성이 떨어질 수 있다.

2. 복잡한 동적 SQL문 같은 경우, 순수 JPA만으로는 부족한 부분이 있어 외부 라이브러리를 활용해야 한다.

- 조건이 많은 동적 쿼리는 순수 JPA만으로 작성하기 불편하기 때문에 보통 QueryDSL, MyBatis 같은 추가 기술을 사용한다.


 

엔티티의 영속성 컨텍스트(Persistence Context)

 

구분 상태 변화 JPA
entity를 entityManager에게 맡기는 행위 (엔티티 영속화) 비영속 → 영속  persist()
영속성 컨텍스트 관리 중단 영속 상태 → 준영속 상태 detach()
영속성 컨텍스트 전체 초기화 모든 엔티티 → 준영속 상태 clear()
EntityManager(영속성 컨텍스트) 종료  영속성 컨텍스트 종료 close()
기존 준영속 객체를 다시 영속으로 만드는 것이 아니라
새로운 영속 객체를 반환
준영속 엔티티 → 새로운 영속 엔티티 생성 merge()
영속 상태의 엔티티 삭제 요청
commit 또는 flush 시 DB에서 삭제
영속 상태 → 삭제 상태 remove()

 

 

영속성 컨텍스트는 PK를 기준으로 엔티티를 관리한다.
이미 영속성 컨텍스트에 존재하는 엔티티를 조회하면 DB 조회 없이 반환하고,
존재하지 않는 경우 DB에서 조회한 뒤 영속성 컨텍스트에 저장한 후 반환한다.

'JPA' 카테고리의 다른 글

[JPA] 복합키 매핑 방법 정리 (EmbeddedId vs IdClass)  (0) 2026.03.16