JPA 소개
- SQL을 직접 다룰 때 발생하는 문제점
- 개발자는 객체지향 애플리케이션과 데이터베이스 중간에서 객체 모델링과 관계형 데이터베이스의 다른 구조를 가지므로
CRUD를 위해 너무 많은 SQL과 JDBC API를 위한 데이터 접근 계층 코드를 작성해 변환 작업을 직접 해야 함 - 요구사항이 추가되었을 때 필드를 추가하기 위해 많은 SQL과 JDBC API 코드 수정이 필요하며
연관된 객체를 사용 가능 여부도 SQL에 전적으로 달리게 되므로 SQL에 모든 것을 강하게 의존하게 됨 - 이를 해결하기 위해서는 JPA가 제공하는 API를 사용해 개발자 대신 JPA가 매핑 정보를 보고 적절한 SQL을 생성하도록 함
- 개발자는 객체지향 애플리케이션과 데이터베이스 중간에서 객체 모델링과 관계형 데이터베이스의 다른 구조를 가지므로
- 패러다임의 불일치
- 객체와 관계형 데이터베이스는 지향하는 목적이 서로 다르므로 둘의 기능과 표현 방법이 달라 패러다임 불일치 문제가 발생
- 객체는 상속이라는 기능을 가지고 있지만 테이블은 상속이라는 기능이 없음
JPA를 사용하면 상속과 관련된 패러다임 불일치를 개발자 대신 해결해주며 객체를 저장하듯이 JPA에 객체 저장 가능 - 객체는 참조라는 기능을 가지고 다른 객체와 연관관계를 가지고 참조에 접근해서 연관된 객체를 조회하지만
테이블은 외래 키를 사용해서 다른 테이블과 연관관계를 가지고 조인을 사용해서 연관된 테이블을 조회하므로
참조를 사용하는 객체와 외래 키를 사용하는 관계형 데이터베이스 사이의 패러다임 불일치가 발생함
JPA를 사용하면 객체를 조회할 때 참조를 외래 키로 변환해서 적절한 SQL을 데이터베이스에 전달 가능 - 객체는 참조를 사용해 객체 그래프 탐색을 할 수 있으나 SQL에 따라 어디까지 탐색할 수 있는지가 종속되어 정해지므로
객체지향 개발자에겐 너무 큰 제약이 되어 언제 끊어질지 모르는 객체 그래프를 함부로 탐색할 수 없게 됨
JPA를 사용하면 연관된 객체를 사용하는 시점에 적절한 SQL을 실행하므로 연관된 객체를 마음껏 조회 가능 - 데이터베이스는 기본 키의 값으로 로우를 구분하고 객체는 동일성/동등성 비교를 하므로 패러다임 불일치 문제가 발생
JPA를 사용하면 같은 트랜잭션일 때 같은 객체가 조회되는 것을 보장 가능
- JPA란 무엇인가?
- ORM(Object Relational Mapping)은 객체와 관계형 데이터베이스를 매핑한다는 뜻이며,
ORM 프레임워크는 객체와 테이블을 매핑해서 패러다임 불일치 문제를 개발자 대신 해결 - JPA는 자바 ORM 기술에 대한 표준 명세로 JAVA에서 제공하는 API (Java Persistence API)로
자바 진영의 ORM 기술 표준으로 애플리케이션과 JDBC 사이에서 동작 - 이전의 데이터 중심 모델에서 벗어나 객체 중심의 개발을 가능하게 해주는 ORM 기술 표준인 JPA를 사용하면
지루하고 반복적인 CRUD SQL을 알아서 처리하고 자동으로 SQL을 만들어서 매핑하므로 패러다임 불일치 해결 가능 - JPA는 생산성, 유지보수, 패러다임의 불일치 해결, 성능, 데이터 접근 추상화와 벤더 독립성, 표준 부분에서 장점을 가짐
- ORM(Object Relational Mapping)은 객체와 관계형 데이터베이스를 매핑한다는 뜻이며,
/* JPA */
// 저장 기능
jpa.persist(member);
// 조회 기능
String memberId = "helloId";
Member member = jpa.find(Member.class, memberId);
// 수정 기능
Member member = jpa.find(Member.class, memberId);
member.setName("이름변경")
// 연관된 객체 조회
Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam();
JPA 시작
- 라이브러리와 프로젝트 구조
- 필요한 모든 라이브러리 자원을 관리하기 위한 도구로 메이븐을 사용하며
pom.xml에 사용할 라이브러리를 적어주면 라이브러리 jar 파일을 자동으로 내려받아 관리하며 빌드 기능을 제공함 - JPA는 하이버네이트라는 오픈소스 ORM 프레임워크를 기반으로 만들어진 자바 ORM 기술 표준이며
JPA 구현체로 하이버네이트를 사용하기 위한 핵심 라이브러리 3개로는
hibernate-core, hibernate-entitymanager, hibernate-jpa-2.1-api가 존재 - pom.xml의 <dependencies>에 사용할 라이브러리를 지정하고
groupId + artifactId + version을 적어 라이브러리를 메이븐 공식 저장소로부터 내려받음
- 필요한 모든 라이브러리 자원을 관리하기 위한 도구로 메이븐을 사용하며
- 객체 매핑
- ID, NAME, AGE를 가진 회원 테이블을 생성한 후,
JPA를 사용하기 위한 매핑 정보를 참고하여 매핑 정보를 표시하는 어노테이션을 가지고 회원 클래스와 회원 테이블을 매핑 - JPA 어노테이션으로는 @Entity, @Table, @Id, @Column 등이 존재하며
JPA는 매핑 정보 덕분에 어떤 엔티티를 어떤 테이블에 저장해야하는지 알 수 있게 됨
- ID, NAME, AGE를 가진 회원 테이블을 생성한 후,
- persistence.xml 설정
- JPA는 persistence.xml을 사용해 필요한 설정 정보를 관리
- JPA 설정으로는 필수 속성, 하이버네이트 속성, 옵션 등이 존재하며
필수 속성으로는 JDBC 드라이버, 데이터베이스 접속 아이디, 데이터베이스 접속 비밀번호, 데이터베이스 접속 URL,
하이버네이트 속성으로는 데이터베이스 방언 설정,
옵션으로는 하이버네이트가 실행한 SQL 출력, SQL 보기 쉽게 정렬, 쿼리를 출력 시 주석 함께 출력, 키 생성 전략 등이 존재 - JPA는 특정 데이터베이스에 종속적이지 않은 기술이므로 다른 데이터베이스로 손쉽게 교체가 가능하며
데이터베이스 방언만 교체하면 특정 데이터베이스에 의존적인 SQL은 데이터베이스 방언이 처리해주게 됨
- 애플리케이션 개발
- 객체 매핑과 JPA 설정을 완료한 후, JPA 애플리케이션을 개발
- 코드는 엔티티 매니저 설정, 트랜잭션 관리, 비즈니스 로직으로 크게 3부분으로 나뉘게 됨
- JPA를 시작하려면 persistence.xml의 설정 정보를 사용하여 엔티티 매니저 팩토리를 생성하고
엔티티 매니저 팩토리에서 엔티티 매니저를 생성하여 JPA의 대부분의 기능인 등록/수정/삭제/조회 등을 제공하게 됨
이후 사용이 끝난 엔티티 매니저는 반드시 종료해야 하며, 애플리케이션을 종료할 때 엔티티 매니저 팩토리 종료도 필요 - JPA를 사용하면 항상 트랜잭션 안에서 데이터를 변경해야만 함
트랜잭션을 시작하려면 엔티티 매니저에서 트랜잭션 API를 받아온 후
비즈니스 로직이 정상 동작하면 트랜잭션을 커밋하고 예외가 발생하면 트랜잭션을 롤백함 - 비즈니스 로직에서는 회원 엔티티를 생성한 후
엔티티 매니저를 통해 JPA를 사용하여 데이터베이스 등록, 수정, 삭제, 조회를 하도록 함
영속성 관리
- 엔티티 매니저 팩토리와 엔티티 매니저
- 엔티티 매니저 팩토리는 persistence.xml에 있는 정보를 바탕으로 엔티티 매니저를 만드는 공장
- 엔티티 매니저는 엔티티를 관리하는 관리자로 엔티티의 저장, 수정, 삭제, 조회 등 엔티티와 관련된 모든 일을 처리
- JPA 구현체들은 엔티티 매니저 팩토리를 생성할 때 커넥션 풀을 생성하고
엔티티 매니저는 데이터베이스 연결이 꼭 필요한 시점인 트랜잭션 시작 시 커넥션을 획득하게 됨
- 영속성 컨텍스트
- 엔티티를 영구 저장하는 환경을 뜻하며
엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 접근, 관리함 - 엔티티 매니저를 생성하면 하나의 영속성 컨텍스트가 생성됨
- 엔티티를 영구 저장하는 환경을 뜻하며
- 엔티티의 생명주기
- 비영속, 영속, 준영속, 삭제로 4가지 상태가 존재
- 비영속은 엔티티를 생성만 하고 저장하지 않아 영속성 컨텍스트와 전혀 관계가 없는 상태,
영속은 엔티티 매니저를 통해 엔티티가 영속성 컨텍스트에 저장/조회되어 영속성 컨텍스트에 의해 관리되는 상태,
준영속은 detach(), close(), clear()로 인해 엔티티가 영속성 컨텍스트에 저장되었다가 분리된 상태,
삭제는 엔티티가 컨텍스트와 데이터베이스에서 삭제된 상태를 뜻함
- 영속성 컨텍스트의 특징
- 영속성 컨텍스트는 엔티티를 식별자 값으로 구분하므로 영속 상태는 반드시 식별자 값이 있어야 함
- 영속성 컨텍스트에 엔티티를 저장하면 트랜잭션을 커밋하는 순간 데이터베이스에 엔티티를 반영하여 저장하는 플러시를 함
- 영속성 컨텍스트가 엔티티를 관리할 때
1차 캐시, 동일성 보장, 트랜잭션을 지원하는 쓰기 지연, 변경 감지, 지연 로딩이라는 5가지 장점이 존재 - 영속성 컨텍스트는 내부에 1차 캐시를 가지고 있으며 영속 상태의 엔티티를 모두 이곳에 저장하므로
엔티티를 조회할 때 먼저 1차 캐시에서 엔티티를 찾고, 1차 캐시에 없다면 데이터베이스에서 조회하므로 성능상 이점 존재 - 식별자가 같은 엔티티 인스턴스를 조회해 비교할 경우 1차 캐시에 있는 같은 엔티티 인스턴스를 반환하므로 동일성을 보장
- 엔티티 매니저를 사용해서 엔티티를 영속성 컨텍스트에 등록하면 트랜잭션을 커밋하기 직전까지 쓰기 지연 SQL 저장소에
SQL을 모아둔 후 커밋할 때 모아둔 쿼리를 데이터베이스에 보내는 쓰기 지연을 지원해 성능 최적화 가능 - JPA로 엔티티를 수정할 때는 단순히 엔티티를 조회해서 데이터만 변경해두면
엔티티의 변경사항을 데이터베이스에서 자동으로 반영하는 변경 감지 기능으로 인해 데이터베이스에 반영되게 됨 - 엔티티를 삭제할 때는 삭제 대상 엔티티를 조회하고 em.remove()를 호출하는 순간 영속성 컨텍스트에서 제거되고
트랜잭션을 커밋해서 플러시를 호출하면 실제 데이터베이스에서 삭제되게 됨
- 플러시
- 플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 작업을 진행
- 영속성 컨텍스트를 플러시하는 방법에는
직접 호출, 트랜잭션 커밋 시 플러시 자동 호출, JPQL 쿼리 실행 시 플러시 자동 호출 3가지가 존재 - 플러시 모드 옵션을 직접 지정하기 위해서는 javax.persistence.FlushModeType를 사용하며
커밋이나 쿼리를 실행할 때 플러시하려면 AUTO, 커밋할 때만 플러시하려면 COMMIT를 사용
- 준영속
- 영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 것이므로
준영속 상태의 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없음 - 영속 상태의 엔티티를 준영속 상태로 만드는 방법에는 특정 엔티티만 준영속 상태로 전환하는 em.detach(),
영속성 컨텍스트를 완전히 초기화하는 em.clear(), 영속성 컨텍스트를 종료하는 em.close() 3가지가 존재 - 준영속 상태는 거의 비영속 상태에 가까워 지연 로딩 등을 할 수 없지만 한 번 영속 상태였으므로 식별자 값을 가지고 있음
- 준영속 상태의 엔티티를 다시 영속 상태로 변경하기 위해서는 merge()를 사용한 병합을 하며
merge()는 준영속 상태의 엔티티를 받아서 그 정보로 새로운 영속 상태의 엔티티를 반환하게 됨
또한 merge()는 비영속 엔티티도 영속 상태로 만드는 비영속 병합이 가능함
- 영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 것이므로
엔티티 매핑
- @Entity
- JPA를 사용해서 테이블과 매핑할 클래스에 붙여주는 어노테이션
- 기본 생성자는 필수이며 name 속성을 사용해 사용할 엔티티의 이름을 지정할 수 있음
- @Table
- 엔티티를 매핑할 테이블을 지정하는 어노테이션
- name 속성을 사용해 매핑할 테이블 이름을 지정,
catalog 속성을 사용해 catalog 기능이 있는 데이터베이스에서 catalog를 매핑,
schema 속성을 사용해 schema 기능이 있는 데이터베이스에서 schema를 매핑,
uniqueConstraints(DDL) 속성을 사용해 DDL 생성 시 유니크 제약 조건 생성 가능
- 다양한 매핑
- 데이터베이스 스키마 자동 생성을 사용해서 엔티티만 만들고 테이블을 자동 생성하기 위한 엔티티와 어노테이션을 작성
- 데이터베이스 스키마 자동 생성
- JPA는 클래스의 매핑 정보와 데이터베이스 방언을 사용해서 데이터베이스 스키마를 자동으로 생성하는 기능을 제공
- 스키마 자동 생성 기능을 사용하기 위해서는 persistence.xml에 hibernate.hbm2ddl.auto 속성을 추가해야 함
- hibernate.hbm2ddl.auto 속성에는
기존 테이블을 삭제하고 새로 생성하는 create,
create에 추가로 애플리케이션을 종료할 때 생성한 DDL을 제거하는 create-drop,
데이터베이스 테이블과 엔티티 매핑 정보를 비교해서 변경 사항만 수정하는 update,
데이터베이스 테이블과 엔티티 매핑 정보를 비교해서 차이가 있으면 경고만 남기고 애플리케이션을 종료하는 validate,
자동 생성 기능을 사용하지 않는 none이 존재 - 스키마 자동 생성 기능은 데이터베이스 테이블이 자동으로 생성되어 개발자의 수고를 덜 수 있으므로
객체와 테이블 매핑을 위해 참고하는 정도로만 사용하는 것이 좋음
- DDL 생성 기능
- @Column 어노테이션과 @Table 어노테이션의 속성을 통해
스키마 자동 생성하기를 통해 만들어지는 DDL에 not null, 문자 크기 제약 조건, 유니크 제약 조건 등을 추가할 수 있음
- @Column 어노테이션과 @Table 어노테이션의 속성을 통해
- 기본 키 매핑
- 회원의 기본 키를 애플리케이션에 직접 할당하는 것 대신 데이터베이스가 생성해주는 값을 사용할 수 있음
- 기본 키 직접 할당 전략을 사용하기 위해서는 @Id를 사용해 기본 키를 애플리케이션에 직접 할당할 수 있음
- 기본 키 자동 생성 전략을 사용하기 위해서는 @Id에 @GeneratedValue를 추가하고 원하는 키 생성 전략을 선택할 수 있음
키 생성 전략에는 기본 키 생성을 데이터베이스에 위임하는 IDENTITY 전략,
데이터베이스 시퀀스를 사용해서 기본 키를 할당하는 SEQUENCE 전략,
키 생성 용도로 사용할 테이블을 만들어서 사용하는 TABLE 전략,
선택한 데이터베이스 방언에 따라 전략 중 하나를 자동으로 선택하는 AUTO 전략이 존재
- 필드와 컬럼 매핑
- JPA가 제공하는 필드와 컬럼 매핑용 어노테이션이 존재
- 컬럼을 매핑하는 @Column
- 자바의 enum 타입을 매핑하는 @Enumerated
- 날짜 타입을 매핑하는 @Temporal
- BLOB, CLOB 타입을 매핑하는 @Lob
- 객체에 임시로 어떤 값을 보관하기 위한 @Transient
- JPA가 엔티티에 접근하는 방식을 지정하는 @Access
+) 자세한 설명 자료
'Community > SOLUX' 카테고리의 다른 글
[221208-221214] 2022 2학기 프로젝트 - 3차 스터디 (0) | 2022.12.14 |
---|---|
[221201-221207] 2022 2학기 프로젝트 - 2차 스터디 (0) | 2022.12.05 |
[221123] 2022 2학기 프로젝트 - 5차 회의 (0) | 2022.11.23 |
[221118] 2022 2학기 프로젝트 - 프로젝트 기획 발표회 (0) | 2022.11.18 |
[221109] 2022 2학기 프로젝트 - 4차 회의 (0) | 2022.11.15 |