02. JPA 시작
01. Hello JPA - 프로젝트 생성
1. H2 데이터베이스 설치와 실행
2. 메이븐 소개
3. 프로젝트 생성
4. 라이브러리 추가 pom.xml
5. JPA 설정하기 - persistence.xml
6. 데이터베이스 방언
- JPA는 특정 데이터베이스에 종속 X
- 각각의 데이터베이스가 제공하는 SQL 문법과 함수는 조금씩 다름
- 방언: SQL 표준을 따르지 않는 각 DB만의 고유한 기능
- ex) MySQL, Oracle SQL, H2 SQL
- hibernate.dialect 속성에 지정 (각각의 DB특성에 매핑되어 있음)
02. Hello JPA - 애플리케이션 개발
1. JPA 구동 방식
- Persistence Class에서 META-INF/persistence.xml 설정 정보를 읽음.
- EntityManagerFactory Class 생성
- 필요할때마다 EntityManagerFactory에서 EntityManger 생성
2. JPA 동작 확인
- JpaMain 클래스 생성
객체와 테이블을 생성하고 매핑하기
- @Entity: JPA가 관리할 객체
- @Id: DB PK와 매핑
create table Member(
id bigint not null,
name varchar(255),
primary key (id)
);
package hellojpa;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Member {
@Id
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;
}
}
EntityManagerFactory 애플리케이션 로딩 시점에 딱 하나만 만들어야 함. 실제 DB에 저장하는 트랜잭션 단위 DB 커넥션을 얻어서 쿼리를 날려서 종료되는 일관적인 작업을 할때마다 EntityManager를 생성해야 함.
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
Member member = new Member();
em.persist(member); // 저장
em.close();
emf.close();
}
}
error: ids for this class must be manually assigned
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
Member member = new Member();
member.setId(1L);
member.setName("HelloA");
em.persist(member); // 저장
em.close();
emf.close();
}
}
JPA에서 트랜잭션 단위가 정말 중요함.
모든 데이터를 변경하는 모든 작업은 트랜잭션 안에서 작업을 해야함
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
tx.begin(); // DB 트랜잭션 시작
Member member = new Member();
member.setId(1L);
member.setName("HelloA");
em.persist(member); // 저장
tx.commit(); // DB 커밋
em.close();
emf.close();
}
}
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
tx.begin(); // DB 트랜잭션 시작
Member member = new Member();
member.setId(1L);
member.setName("HelloA");
em.persist(member); // 저장
tx.commit(); // DB 커밋
em.close();
emf.close();
}
}
정상적으로 SQL 쿼리문이 실행되는 것을 확인할 수 있음.
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(name, id)
values
(?, ?)
실제 DB에서 쿼리문을 날려서 실행을 해보면 정상적으로 저장이 된 것을 확인 할 수 있음
값을 하나 더 넣어주면 저장이 잘 되는 것을 확인 가능
member.setId(2L);
member.setName("HelloB");
쿼리를 만든 적이 없고 JPA가 매핑 정보를 보고 알아서 넣어줌
정석 코드
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
tx.begin(); // DB 트랜잭션 시작
try {
Member member = new Member();
member.setId(2L);
member.setName("HelloB");
em.persist(member); // 저장
tx.commit(); // DB 커밋
} catch (Exception e) {
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
- 조회
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
tx.begin(); // DB 트랜잭션 시작
try {
Member findMember = em.find(Member.class, 1L);
System.out.println("findMember.id = " + findMember.getId());
System.out.println("findMember.name = " + findMember.getName());
tx.commit(); // DB 커밋
} catch (Exception e) {
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
실행을 하면 다음과 같이 쿼리문이 나오는 걸 확인할 수 있음.
Hibernate:
select
member0_.id as id1_0_0_,
member0_.name as name2_0_0_
from
Member member0_
where
member0_.id=?
findMember.id = 1
findMember.name = HelloA
- 삭제
em.remove(); - 수정
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
tx.begin(); // DB 트랜잭션 시작
try {
Member findMember = em.find(Member.class, 1L);
findMember.setName("HelloJPA");
tx.commit(); // DB 커밋
} catch (Exception e) {
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
실행 결과: Update 쿼리문이 실행 되는 걸 확인할 수 있음.
Hibernate:
select
member0_.id as id1_0_0_,
member0_.name as name2_0_0_
from
Member member0_
where
member0_.id=?
Hibernate:
/* update
hellojpa.Member */ update
Member
set
name=?
where
id=?
실제 DB에서 조회를 해보면 값이 변경된 것을 확인할 수 있음.
why?
- JPA를 통해서 Entity를 가져오면 JPA가 관리를 함.
- JPA가 변경이 되었는지 트랜잭션을 commit하는 시점에서 체크를 함.
- 바뀌었으면 트랜잭션 commit 하기 직전에 Update 쿼리를 만들어 날리고 트랜잭션이 커밋됨.
주의
- EntityManagerFactory는 웹서버가 올라오는 시점에서 DB당 하나가 생성이 됨
- EntityManger라는 것은 고객의 요청이 올때마다 계속 사용했다가 버렸다가 동작
조심해야 할 부분: 쓰레드간에 절대 공유해서는 안됨 - 장애가 발생(사용하고 버려야 한다.) - JPA의 모든 데이터 변경은 트랜잭션 안에서 실행
- 내부적으로 DB가 트랜잭션 쿼리를 다 처리
JPQL 소개
- 가장 단순한 조회 방법
- EntityManager.find()
- 객체 그래프 탐색(a.getB().getC()) - 나이가 18살 이상인 회원을 모두 검색하고 싶다면?
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
tx.begin(); // DB 트랜잭션 시작
try {
// Member findMember = em.find(Member.class, 1L);
// findMember.setName("HelloJPA");
List<Member> result = em.createQuery("select m from Member as m", Member.class)
.getResultList();
for (Member member : result) {
System.out.println("member.names = " + member.getName());
}
tx.commit(); // DB 커밋
} catch (Exception e) {
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
아래와 같은 결과값이 나오는 것을 확인할 수 있다.
Hibernate:
/* select
m
from
Member as m */ select
member0_.id as id1_0_,
member0_.name as name2_0_
from
Member member0_
member.names = HelloJPA
member.names = HelloB
이거의 장점이 뭐지?
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
tx.begin(); // DB 트랜잭션 시작
try {
// Member findMember = em.find(Member.class, 1L);
// findMember.setName("HelloJPA");
List<Member> result = em.createQuery("select m from Member as m", Member.class)
.setFirstResult(5)
.setMaxResults(10)
.getResultList();
for (Member member : result) {
System.out.println("member.names = " + member.getName());
}
tx.commit(); // DB 커밋
} catch (Exception e) {
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
JPQL: 객체를 대상으로 하는 객체지향 쿼리이기 때문에 DB의 방언에 맞게 매핑을 해서 쿼리문을 날려줌.
package hellojpa;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
//code
EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
tx.begin(); // DB 트랜잭션 시작
try {
// Member findMember = em.find(Member.class, 1L);
// findMember.setName("HelloJPA");
List<Member> result = em.createQuery("select m from Member as m", Member.class)
.setFirstResult(5)
.setMaxResults(10)
.getResultList();
for (Member member : result) {
System.out.println("member.names = " + member.getName());
}
tx.commit(); // DB 커밋
} catch (Exception e) {
tx.rollback();
}finally {
em.close();
}
emf.close();
}
}
실습 - JPQL 소개
• JPQL로 전체 회원 검색
• JPQL로 ID가 2 이상인 회원만 검색
• JPQL로 이름이 같은 회원만 검색
• JPQL에 대해 자세한 내용은 객체지향 쿼리에서 학습
JPA를 사용하면 엔티티 객체를 중심으로 개발
• 문제는 검색 쿼리
• 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
(why? 테이블을 가져오면 JPA의 사상이 깨지니까)
• 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
• 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검
색 조건이 포함된 SQL이 필요(실제 RDB에 있는 물리적인 DB에 쿼리를 날리면 그 DB에 종속적으로 설계가 되기 때문에 엔티티 객체를 대상으로 하는 쿼리를 날리는 JPQL 사용)
JPQL
• JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공
• SQL과 문법 유사, SELECT, FROM, WHERE, GROUP BY,
HAVING, JOIN 지원
• JPQL은 엔티티 객체를 대상으로 쿼리
• SQL은 데이터베이스 테이블을 대상으로 쿼리
테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리
• SQL을 추상화해서 특정 데이터베이스 SQL에 의존X
• JPQL을 한마디로 정의하면 객체 지향 SQL
• JPQL은 뒤에서 아주 자세히 다룸
- Jpa 동작 확인
Author And Source
이 문제에 관하여(02. JPA 시작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@raesong/02.-JPA-시작저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)