[Java Spring] - JPA
JPA (Java Persistent API)
Spring JDBC(Java Database Connectivity)
- DB에 접근(Connectivity)할 수 있도록 Java에서 제공하는 API
- Spring JDBC는 DriveManager가 하는 일들을
JdbcTemplate
에게 맡김- JdbcTemplate : 템플릿 메소드 패턴이 적용된 클래스이다.
- JDBC는 DBMS 벤더에 의존하지 않고 통합된 코드를 사용하여 제어할 수 있다.
단계
- JDBC Driver loading (벤더에 맞는 데이터 베이스 드라이버 로딩)
- Connection : DB 연결
- Statement : SQL 구문 정의, 값 세팅
executeUpdate()
orexecuteQuery()
- ResultSet : 조회인 경우
- close : Connection, Statement, ResultSet
SQL Mapper(MyBatis), ORM
- Mybatis는 자바 오브젝트와 SQL사이의 자동 매핑 기능을 지원하는 ORM프레임워크이다.
MyBatis
- MyBatis에서는 프로그램에 있는 SQL 쿼리들을 별도의 파일에 구성하여 프로그램 코드와 SQL을 분리할 수 있는 장점을 가지고 있다.
- 대부분의 JDBC 기능을 제공하며, JDBC API를 보다 간결한 코드로 편하게 사용할 수 있다. - 쿼리가 수정되면 DTO와 함께 수정해야 하는 문제 (논리적 의존관계)
ORM(Object-Relational Mapping)
- 객체와 데이터베이스의 데이터를 자동으로 매핑.
- 애플리케이션과 데이터베이스 사이 mapping을 통해 엔티티 클래스 객체에 포함된 정보를 테이블에 저장하는 기술이다.
JPA, Hibernate
JPA
- 자바 ORM에 대한 API 표준 명세로, 자바 코드를 사용해서 데이터베이스에 접근이 가능하게 함
- 구현체 예 : hibernate, EclipseLink, DataNucleus
- 자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스
- 스프링이 제공하는 API가 아닌 자바가 제공하는 API다.
- 스프링 부트에서는 spring-boot-starter-data-jpa로 패키지를 가져와 사용하며, Hibernate 프레임워크를 활용한다.
- 개발자는 JPA를 활용하여 JDBC API를 통해 SQL을 호출하여 데이터베이스에 접근한다.
장점
- 생산성
- SQL 쿼리를 직접 생성하지 않고, JPA에 저장할 객체를 전달하고 JPA 메소드를 활용해 데이터 베이스를 다룰 수 있다.
- SQL을 작성하고 JDBC API를 사용하는 반복적인 일을 JPA에서 대신해준다.
- 유지보수
- 유지 보수 측면에서 SQL의존적인 개발은 엔티티 컬럼이 변경되는 상황에서 연관된 모든 SQL문을 수정해야하고 결과를 매핑하기 위한 JDBC API도 변경해야 한다.
- JPA는 JPA에서는 엔티티 클래스 정보만 변경하면 된다.
- 성능 :
- JPA는 애플리케이션과 데이터 베이스 사이에서 동작하기 때문에 다양한 성능 최적화 기회를 제공한다. 예를 들어서 같은 트랜잭션 내에서는 캐싱 기능을 제공한다.
- 패러다임 불일치 문제 해결 :
- 데이터 베이스는 데이터 중심으로 구조화되어있어 객체 지향 언어와 패러다임 불일치 문제가 발생한다.
- JPA는 데이터 베이스에 맞춰 데이터를 저장하기위해 객체를 매핑하는 과정에서 드는 비용을 없애 좀 더 객체지향적인 개발이 가능하게 한다.
- DB벤더 독립성 :
- SQL 의존적인 개발은 DB벤더마다 문법이 다르기 때문에 다른 데이터베이스로 변경하는 작업이 어렵다.
- JPA는 데이터베이스와 애플리케이션 사이에서 추상화 데이터 접근 계층을 제공하므로 변경 작업이 비교적 간편하다.
- 예) 로컬 개발 환경은 H2데이터 베이스 사용, 개발이나 상용 환경은 MYSQL 사용
단점
- JPA는 복잡한 쿼리보다는 실시간 쿼리에 최적화되어있다. 통계 처리와 같은 복잡한 작업이 필요한 경우에는 JPA가 제공하는 네이티브 SQL을 사용하거나, 기존의 Mybatis와 같은 Mapper 방식이 더 효율적일 수 있다.
- 자동 생성되는 쿼리문이 많아 성능 최적화가 필요할 수 있다.
- Persistent Context에서 1차 Cache, Write Behind, Dirty Checking, Lazy Loading 등의 다양한 기능을 지원해주기 때문에 해당 개념을 잘 모르고 JPA를 사용했을 경우 수 많은 예외와 성능 감소가 발생할 수 있다.
hibernate
- JPA라는 명세의 구현체
- JPA의 인터페이스를 구현하여 객체와 데이터베이스 간의 매핑을 처리
- Hibernate는 SQL을 자동으로 생성하고 실행하여 데이터베이스에 대한 접근을 관리한다.
영속성 컨텍스트(Persistent Context)
- 테이블과 매핑되는 엔티티 객체 정보를 어플리케이션 내에 오래 지속되도록 저장하는 환경이다.
- Spring에서
EntityManager
를 주입해 사용할 수 있다.
생명주기
- 비영속(new/transient)
- 영속성 컨텍스트 및 데이터베이스와 전혀 관계가 없는 상태
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
- 영속(managed)
- 영속성 컨텍스트에 저장된 상태
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(member); // 객체를 저장한 상태(영속)
- 준영속(detached)
- 영속성 컨텍스트에 저장되었다가 분리된 상태
- 실제 데이터가 삭제되지는 않지만 1차캐시부터 쓰기 지연 저장소까지 해당 엔티티를 관리하기 위한 모든 정보가 제거
em.detach(member);
- 삭제(removed)
- 삭제된 상태
em.remove(member);
기능
- 1차 캐시
- 영속성 컨텍스트 내부에 엔티티를 저장하는 캐시 메커니즘
- 영속 상태인 엔티티에 대한 조회는 캐시에서 진행되므로 성능 향상을 가져옴
- 변경 감지
- 엔티티의 변경을 감지하여 자동으로 데이터베이스와 동기화
- 지연 로딩
- 엔티티가 실제로 필요한 시점까지 데이터베이스에서 조회하지 않는 기능으로, 성능 최적화에 도움
- 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
즉시 / 지연 로딩
- 지연 로딩
- 연관된 엔티티를 처음으로 접근할 때까지 데이터베이스 조회를 지연시킴
- 연관된 엔티티가 실제로 필요한 시점에만 데이터베이스를 조회하므로, 불필요한 조회를 피하고 성능 최적화
- 초기 로딩 시간이 적어지고 메모리 소비량 감소
- 초기화가 지연되면 원하지 않는 순간 성능에 영향을 줄 수 있다.
설정
- @ManyToOne 은 기본값이 즉시로딩이고, @OnetoMany는 지연로딩이다.
- JPA에서
fetch = FetchType.LAZY
옵션을 지정해 설정할 수 있다.- 필요한 경우
fetch = FetchType.EAGER
옵션을 사용하여 즉시 로딩으로 변경 가능
- 필요한 경우
주의 사항
- 지연 로딩을 사용할 때는 영속성 컨텍스트가 엔티티를 관리하고 있는 상태여야 한다.
- 지연 로딩을 사용하는 엔티티에 대한 접근은 영속성 컨텍스트의 범위 내에서 이루어져야 한다.
- 지연 로딩을 사용하면서 영속성 컨텍스트 범위를 벗어나는 경우에는 예외가 발생할 수 있다.
Leave a comment