목차
- JPA 구동 방식
- JPA 동작 확인(CRUD)
- JPA 주의점
- JPQL 소개
JPA 구동 방식
- Persistence 클래스에서 시작
- persistence.xml 에서 설정 정보를 읽고 EntityManagerFactory 생성
- 필요할 때마다 EntityManager 찍어서 돌리면 됨.
JPA 동작 확인
- JpaMain 클래스 생성
- JPA 동작 확인
JpaMain
public class JpaMain {
public static void main(String[] args) {
// persistence.xml의 Unit Name 넘기기
// <persistence-unit name="hello">
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManagerFactory에서 EntityManager 꺼내기
EntityManager em = emf.createEntityManager();
//실제 동작하는 코드 작성(DB 저장, 조회 같은)
// EntityManager 종료
em.close();
// EntityManagerFactory 종료
emf.close();
}
}
테이블을 생성
create table Member (
id bigint not null,
name varchar(255),
primary key (id)
);
객체 생성 후 테이블과 매핑하기
package hellojpa;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity // JPA가 관리해야 하는 대상 인식
public class Member {
@Id // PK 알려주기
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- @Entity: JPA가 관리할 객체
- @Id: 데이터베이스 PK와 매핑
회원 추가 (오류)
package hellojpa;
import jakarta.persistence.*;
public class JpaMain {
public static void main(String[] args) {
// persistence.xml의 Unit Name 넘기기
// <persistence-unit name="hello">
// application 로딩 시점에 딱 하나를 만들어야 함
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManagerFactory에서 EntityManager 꺼내기
// DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
EntityManager em = emf.createEntityManager();
//실제 동작하는 코드 작성(DB 저장, 조회 같은)
Member member = new Member();
member.setId(1L); // PK는 NOT NULL
member.setName("HelloA");
em.persist(member); // Member 저장
// EntityManager 종료
em.close();
// EntityManagerFactory 종료
emf.close();
}
}
- 정상적으로 동작할 것 같지만 오류가 발생한다.
- JPA에서 모든 데이터를 변경하는 작업은 꼭 transaction 안에서 작업해야 한다.
회원 추가 코드 수정
package hellojpa;
import jakarta.persistence.*;
public class JpaMain {
public static void main(String[] args) {
// persistence.xml의 Unit Name 넘기기
// <persistence-unit name="hello">
// application 로딩 시점에 딱 하나를 만들어야 함
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManagerFactory에서 EntityManager 꺼내기
// DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
EntityManager em = emf.createEntityManager();
// 1, 트랜잭션 얻기
EntityTransaction tx = em.getTransaction();
// 2. 트랙잭션 시작
tx.begin();
//실제 동작하는 코드 작성(DB 저장, 조회 같은)
Member member = new Member();
member.setId(1L); // PK는 NOT NULL
member.setName("HelloA");
em.persist(member); // Member 저장
// 3. 커밋
tx.commit();
// EntityManager 종료
em.close();
// EntityManagerFactory 종료
emf.close();
}
}
참고: JPA 설정 정보
<!-- 옵션 -->
<property name="hibernate.show_sql" value="true"/> // SQL 문 보여줌
<property name="hibernate.format_sql" value="true"/> // SQL 문 이쁘게
<property name="hibernate.use_sql_comments" value="true"/> // 쿼리가 어디서 나왔는지(주석 부분)
<property name="hibernate.hbm2ddl.auto" value="create" />
DB 확인
- 하지만 Member 객체가 Member 테이블에 저장하라고 한 적이 없다.
- 이것은 관례를 따른 것이다.
참고: 테이블명과 컬럼명이 다르다면
@Entity
@Table(name = "USER") // user 라는 테이블에 쿼리 날림
public class Member {
@Entity // JPA가 관리해야 하는 대상 인식
@Id // PK 알려주기
private Long id;
Column(name = "username") // 테이블과 컬럼이름과 매핑
private String name;
}
회원 수정
package hellojpa;
import jakarta.persistence.*;
public class JpaMain {
public static void main(String[] args) {
// persistence.xml의 Unit Name 넘기기
// <persistence-unit name="hello">
// application 로딩 시점에 딱 하나를 만들어야 함
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManagerFactory에서 EntityManager 꺼내기
// DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
EntityManager em = emf.createEntityManager();
// 1, 트랜잭션 얻기
EntityTransaction tx = em.getTransaction();
// 2. 트랙잭션 시작
tx.begin();
//실제 동작하는 코드 작성(DB 저장, 조회 같은)
try {
Member findMember = em.find(Member.class, 1L);// 클래스와 PK값 파라미터 전달
System.out.println("findMember.id = " + findMember.getId());
System.out.println("findMember.name = " + findMember.getName());
// 회원 이름 변경
findMember.setName("쌈뽕");
// em.persist(findMember); // Member 저장 안해도 됨!!!!
// 3. 커밋
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
// EntityManager 종료
em.close();
// EntityManagerFactory 종료
emf.close();
}
}
}
- JPA 가 뭔가 바뀌었다고 인지하면 트랜잭션 커밋하기 직전에 업데이트 쿼리를 날리고 커밋이 된다.
- 어마어마한 장점
회원 삭제
package hellojpa;
import jakarta.persistence.*;
public class JpaMain {
public static void main(String[] args) {
// persistence.xml의 Unit Name 넘기기
// <persistence-unit name="hello">
// application 로딩 시점(웹 서버에 올라오는 시점)에 DB당 딱 하나를 만들어야 함
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManagerFactory에서 EntityManager 꺼내기
// DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
EntityManager em = emf.createEntityManager();
// 1, 트랜잭션 얻기
EntityTransaction tx = em.getTransaction();
// 2. 트랙잭션 시작
tx.begin();
//실제 동작하는 코드 작성(DB 저장, 조회 같은)
try {
Member findMember = em.find(Member.class, 1L);// 클래스와 PK값 파라미터 전달
em.remove(findMember); // 회원 삭제
// 3. 커밋
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
// EntityManager 종료
em.close();
// EntityManagerFactory 종료
emf.close();
}
}
}
회원 단건 조회
package hellojpa;
import jakarta.persistence.*;
public class JpaMain {
public static void main(String[] args) {
// persistence.xml의 Unit Name 넘기기
// <persistence-unit name="hello">
// application 로딩 시점에 딱 하나를 만들어야 함
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// EntityManagerFactory에서 EntityManager 꺼내기
// DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
EntityManager em = emf.createEntityManager();
// 1, 트랜잭션 얻기
EntityTransaction tx = em.getTransaction();
// 2. 트랙잭션 시작
tx.begin();
//실제 동작하는 코드 작성(DB 저장, 조회 같은)
try {
Member findMember = em.find(Member.class, 2L);// 클래스와 PK값 파라미터 전달
System.out.println("findMember.getId() = " + findMember.getId());
System.out.println("findMember.getName() = " + findMember.getName());
// 3. 커밋
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
// EntityManager 종료
em.close();
// EntityManagerFactory 종료
emf.close();
}
}
}
findMember.getId() = 2
findMember.getName() = HelloB
주의점
- 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유
- 엔티티 매니저는 쓰레드간에 공유X (사용하고 버려야 한다).
- JPA의 모든 데이터 변경은 트랜잭션 안에서 실행
JPQL 소개
- 가장 단순한 조회 방법
- EntityManager.find()
- 객체 그래프 탐색(a.getB().getC())
- 나이가 18살 이상인 회원을 모두 검색하고 싶다면? (1 ~8 번까지 페이징 처리)
List<Member> result =
em.createQuery("select m from Member m where m.id >= 2", Member.class)
.setFirstResult(1)
.setMaxResults(8)
.getResultList();
JPA를 사용하면 엔티티 객체를 중심으로 개발
- 문제는 검색 쿼리
- 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
- 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
- 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요
JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공
- SQL과 문법 유사, SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원
- JPQL은 엔티티 객체를 대상으로 쿼리
- SQL은 데이터베이스 테이블을 대상으로 쿼리
테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리
- SQL을 추상화해서 특정 데이터베이스 SQL에 의존X
- JPQL을 한마디로 정의하면 객체 지향 SQL
'JPA' 카테고리의 다른 글
[JPA] 엔티티 매핑 (0) | 2024.06.24 |
---|---|
[JPA] 영속성 컨텍스트 (0) | 2024.06.24 |
[JPA] JPA란 뭘까? (0) | 2024.06.23 |
[JPA] 도메인 분석 설계 (0) | 2024.06.20 |
[JPA] 프로젝트 환경 설정 (0) | 2024.06.19 |