JPA는 Interface, Hibernate는 그 구현체
Java Persistence API (JPA)는 인터페이스의 모음이며, 이를 구현한 구현체로 Hibernate라는 라이브러리를 선택했다.
데이터베이스 방언의 유연성
JPA는 데이터베이스에 종속적이지 않다.
각 데이터베이스의 방언을 지원하여, Oracle에서 MySQL로 데이터베이스를 변경해도 큰 영향이 없다. 실제 운영에서는 조그만한 영향이 있으므로 주의가 필요하다.)
JPA의 설정과 초기화
JPA를 사용하기 위해선 persistence.xml을 설정해야 한다. 이 설정 파일을 통해 다음의 단계를 거친다.
1. Persistence 클래스에서 persistence.xml을 읽어 설정 정보를 로드한다.
2. EntityManagerFactory 클래스를 생성한다.
3. EntityManagerFactory에서 EntityManager 인스턴스를 생성한다.
Entity의 정의와 매핑
Entity는 데이터베이스 테이블을 자바 클래스로 매핑하는 역할을 한다.
@Entity, @Table, @Id, @Column 등의 애노테이션을 사용하여 이를 설정할 수 있다.
@Entity
@Getter
public class Member {
@Id
private Long id;
private String name;
}
이렇게 생성하면 기본 규칙에 따라 Member 테이블에 값을 넣고 pk는 @Id가 붙은 id가 pk가 된다.
만약 테이블 명을 JAVA 클래스와 다르게 생성하고 싶다면 아래와 같이 @Table을 사용하면 되고, 컬럼 이름을 변경하고 싶다면 @Column을 사용하면 된다.
@Entity
@Getter
@Table(name = "USER")
public class Member {
@Id
private Long id;
@Column(name = "username")
private String name;
}
Transaction과 EntityManager의 생명주기
JPA에서 데이터를 변경하는 모든 작업은 트랜잭션 내에서 이루어져야 한다.
EntityManager는 내부적으로 DB Connection을 물고 동작하므로, 사용이 끝나면 반드시 닫아주어야 한다.
EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("hello");
EntityManager em = emFactory.createEntityManager();
// code 시작
EntityTransaction tx = em.getTransaction();
tx.begin(); // transaction 시작
try {
Member buildMember = Member.builder()
.id(1L)
.name("abc")
.build();
em.persist(buildMember);
tx.commit(); // 성공하면 커밋
} catch (Exception e) {
tx.rollback(); // 실패하면 롤백
} finally {
em.close();
}
emFactory.close();
이러한 과정을 실제 개발할때는 필요가 없다. Spring이 다 해주기 때문 !!
JPA를 통해 객체를 검색, 삭제, 수정하는 방법
객체 검색
Member findMember = em.find(Member.class, 1L);
객체 삭제
em.remove(findMember); // 삭제
객체 수정
특정 값만을 바꾸기 위해 엔티티에 Setter 애노테이션 작성 후 작업
Member findMember = em.find(Member.class, 1L);
findMember.setName("updateName!!");
코드 실행 후 출력된 쿼리
Hibernate:
select
member0_.id as id1_0_0_,
member0_.name as name2_0_0_
from
Member member0_
where
member0_.id=?
Hibernate:
/* update
reviewjpa.Member */ update
Member
set
name=?
where
id=?
이름을 수정 후 저장을 따로 하지 않았는데 자동으로 업데이트 쿼리가 나갔다. 도대체 어떻게 된걸까?
JPA의 더티 체킹(Dirty Checking)
JPA를 통해서 엔티티를 가져오면 JPA가 관리하게 된다.
JPA가 관리하는 엔티티 객체의 상태가 변경되면, 트랜잭션 커밋 시점에 이를 감지하고 자동으로 SQL 업데이트 쿼리를 실행한다.
※주의※
EntityMangerFactory는 WAS가 올라오는 시점에 DB당 딱 1개만 생성이 된다.
EntityManger는 고객 요청이 올때마다 생성하고 em.close를 하면 버린다. 쓰레드간에 공유하지 않는다.
★JPA의 모든 데이터 변경은 트랜잭션 안에서 실행한다.★ 매우중요!!
JPQL (Java Persistence Query Language)
JPQL은 SQL을 추상화하여, 데이터베이스에 종속적이지 않게 만든다.
이를 통해 객체 지향적인 쿼리가 가능하며, 엔티티 객체를 대상으로 검색을 수행할 수 있다.
JPQL로 전체 회원 검색
em.createQuery로 쿼리를 작성할 수 있다.
JPA 입장에서는 코드를 짤 때 테이블을 대상으로 코드를 절대 짜지 않고 객체를 대상으로 한다.
해당 쿼리는 Member 객체를 다 갖고 오는 것이다.
List<Member> result =
em.createQuery("select m from Member as m", Member.class)
.setFirstResult(3)
.setMaxResults(5)
.getResultList();
여기서 페이징 처리 또한 할 수 있다.
위와 같은 코드를 작성하면 첫 시작은 3부터, 5개 가져오라는 쿼리가 된다. 이것이 sql문으로 어떻게 나오는지 보자
Hibernate:
/* select
m
from
Member as m */ select
member0_.id as id1_0_,
member0_.name as name2_0_
from
Member member0_ limit ? offset ?
persistence.xml 에서 mysql로 설정해놨기 때문에, limit와 offset이 나가게 된다.
Oracle로 바꾸면 어떻게 되는지 보자.
Hibernate:
/* select
m
from
Member as m */ select
*
from
( select
row_.*,
rownum rownum_
from
( select
member0_.id as id1_0_,
member0_.name as name2_0_
from
Member member0_ ) row_
where
rownum <= ?
)
where
rownum_ > ?
쿼리가 Oracle에 맞게 바뀌어서 나간 것을 볼 수 있는데, 이것이 SQL의 방언이다.
JPQL이라는게 객체를 대상으로 하는 객체 지향 쿼리라고 생각하면된다.
검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색한다.
애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.
SQL을 추상화해서 특정 DB SQL에 의존하지 않는다.
JPQL은 추후에 학습할 예정이다.
JPQL VS SQL
JPQL은 엔티티 객체를 대상으로 쿼리를 실행한다.
반면 SQL은 데이터베이스의 테이블을 대상으로 쿼리를 실행한다.
JPQL은 이런 차이점을 두고 있지만, 내부적으로는 적절한 SQL 쿼리로 변환되어 데이터베이스에 전달한다.
JPA의 필요성
객체 지향적인 프로그래밍과 데이터베이스 사이의 간극을 줄이고, 더 효율적인 데이터 관리를 가능하게 해주므로 꼭 학습을 해야한다고 생각한다.
'JPA > ORM 표준 JPA' 카테고리의 다른 글
[ORM 표준 JPA] 6. 연관관계 매핑 1 (0) | 2023.09.23 |
---|---|
[ORM 표준 JPA] 5. 엔티티 매핑2 - 기본키 전략 (0) | 2023.09.20 |
[ORM 표준 JPA] 4. 엔티티 매핑1 - 객체와 테이블 매핑 (0) | 2023.09.18 |
[ORM 표준 JPA] 3. 영속성 관리 - 내부 동작 방식 (0) | 2023.09.16 |
[ORM 표준 JPA 프로그래밍] 1. JPA 등장 배경과 소개 (0) | 2023.09.13 |