이 글은 김영한 님의 Infrean 강의를 학습한 내용을 정리하여 작성합니다.
JPA 구동 방식
0. JPA에는 Persistence라는 클래스가 존재하고 여기서 시작한다.
1. MET-INF/persistence.xml 파일의 설정 정보를 읽는다.
2. EntityManagerFactory 클래스를 생성한다.
3. 필요할 때마다 EntityManager를 생성한다.
실습 - JPA 동작 확인
- JpaMain 클래스 생성
- JPA 동작 확인
Persistence 클래스의 createEntityManagerFactory() 메서드의 인자로 persistenceUnitName이 필요하다.
이때, persistenceUnitName은 이전에 persistence.xml 파일에서 생성한 persistence-unit을 의미한다.
위 이미지처럼 에러가 발생하면 OK!!
※ 주의!
EntityManagerFactory는 application 실행 시점에 단 하나만 생성되어야 한다.
= 엔티티 매니저 팩토리는 하나만 생성해 애플리케이션 전체에서 공유한다.
※ EntityManager 생성
하나의 트랜잭션 단위마다 하나의 EntityManger를 생성해 주어야 한다.
+ 엔티티 매니저는 쓰레드 간에 공유되지 않는다 (사용하고 버려야 한다).
객체와 테이블을 생성하고 매핑하기
H2 데이터베이스에 Member라는 table을 하나 생성한다.
이제 JPA에서 Member와 매핑이 되는 Member라는 클래스를 하나 생성한다.
- @Entity : JPA가 관리할 객체
- @Id : 데이터베이스 PK와 매핑
JpaMain 클래스에 Member 객체 member를 생성한 뒤 em.persist(member); 메서드를 수행하면 데이터베이스에 member 객체가 저장된다.
실행하면 다음과 같은 결과가 나타난다.
ids for this class must be manually assigned before calling save(): hellojpa.Member
이러한 에러가 발생하는 이유는 id를 PK로 설정하였으나 현재 우리가 데이터베이스에 저장하려는 member 객체에는 id값이 없기 때문이다.
id에 값을 추가했음에도 불구하고 계속해서 에러가 발생한다.
JPA에서 데이터를 변경하는 모든 작업은 트랜잭션 내부에서 수행되어야 한다.
= JPA의 모든 데이터 변경은 트랜잭션 안에서 실행되어야 한다.
트랜잭션 (Transaction)
: 하나의 논리적 기능을 수행하기 위한 작업의 단위
- ACID 성질
- Atomicity (원자성)
: 일부만 실행되지 않고 전부 실해오기거나 또는 아무것도 실행되지 않아야 한다.
- Consistency (일관성)
: 실행 후에도 데이터베이스는 일관성이 있다 (모순이 없음).
- Isolation (격리성)
: 트랜잭션 실행 중에 잇는 연산의 중간 결과는 다른 트랜잭션이 접근할 수 없다.
- Durability (영속성)
: 트랜잭션의 결과는 영속적이다.
- Begin (시작) , Commit (완료) , Rollback (복귀)
실행결과를 살펴보면 Member 가 insert 되었다는 주석과 함께 쿼리가 출력된다.
이러한 내용이 출력되는 이유는 이전에 persistence.xml 파일에 다음과 같은 내용을 추가하였기 때문이다.
- show_sql : 쿼리가 출력되도록 한다.
- format_sql : 쿼리를 포맷해서 출력해준다.
- use_sql_comments : /* insert hellojpa.Member */처럼 쿼리가 나타난 이유를 주석으로 출력해준다.
실제 데이터베이스를 확인해보면 데이터가 저장되어 있는 것을 확인할 수 있다.
결과를 확인해보면 실제 우리가 직접 쿼리를 생성한 것은 없다.
JPA가 매핑 정보를 보고 알아서 수행해준다.
Mapping
위 내용을 보면 우리가 Member 클래스를 데이터베이스 Member 테이블에 저장되도록 한 적이 없다.
관례에 따라 Member 클래스가 Member 테이블에 저장된다.
만약 Member 클래스를 User 테이블에 저장하고 싶다면 방법은 다음과 같다.
@Table 어노테이션을 사용한다.
※ DB에 Column 이름이 name이 아닌 userName이라면?
@Column 어노테이션을 사용해 다음과 같이 Mapping 해준다.
/* 보수 작업 */
현재 위에서 작성한 코드는 좋지 않은 코드이다.
왜냐하면 코드 중간에 문제가 생겼을 때 em.close(); emf.close(); 문장이 수행되지 않기 때문이다.
그래서 다음과 같이 변경해준다.
실습
● 조회
실행 결과를 확인해보면 select 쿼리와 함께 id와 name이 정상적으로 출력되는 것을 확인할 수 있다.
● 수정
변경한 내용을 다시 데이터베이스에 저장할 필요가 없음에 주의한다!!
update 쿼리가 수행된 것을 확인할 수 있다.
실제 데이터베이스에도 HelloA가 HelloJPA로 변경된 것을 확인할 수 있다.
● 삭제
EntityManager는 고객의 요청이 올 때마다 생성하고 close() 하는 방식으로 사용된다.
따라서 EntityManager는 절대 쓰레드 간에 공유해서 사용하면 안 된다.
사용되는 즉시 버려야 한다.
JPQL 소개
- 가장 단순한 조회 방법
- EntityManager.find()
- 객체 그래프 탐색(a.getB().getC())
- 나이가 18살 이상인 회원을 모두 검색하고 싶다면?
: JPQL을 사용해야 한다.
* 여기서 대상은 테이블이 아닌 객체임에 유의한다!
-> 쿼리가 우리가 작성한 쿼리와 다르다는 것을 확인할 수 있다.
+ 페이징
1번째부터 10개를 나열함을 의미한다.
- JPA를 사용하면 엔티티 객체를 중심으로 개발한다.
- 문제는 검색 쿼리이다.
- 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색한다.
- 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능하다.
- 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.
- JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다.
- SQL과 문법이 유사하다.
SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원
- JPQL은 엔티티 객체를 대상으로 쿼리 한다.
- SQL은 데이터베이스 테이블을 대상으로 쿼리 한다.
- 테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리이다.
- SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다.
- JPQL을 한마디로 정의하면 객체 지향 SQL
정리
- H2 데이터베이스 실행
- pom.xml에 라이브러리 생성
- persistence.xml
- JPA는 EntityManagerFactory를 만들어 동작해야 한다.
- 고객의 요청에 따른 DB 작업은 EntityManager를 통해 이루어져야 한다.
- 데이터베이스의 모든 정보 변경은 트랜잭션 안에서 이루어져야 한다.
- commit()을 수행해야 한다.
- 자원을 모두 사용하면 닫아주어야 한다.
'JPA > JPA 시작하기' 카테고리의 다른 글
Hello-JPA-프로젝트 생성 (0) | 2022.07.15 |
---|