JPA를 활용해 DB에 저장, 조회, 삭제, 수정해보기
- Spring/JPA
- 2021. 11. 20.
이전 게시글에서 JPA 프로젝트를 생성했다. 프로젝트를 생성한 다음에 간단하게 실행하는 법을 보려고 한다. 이전 게시글은 아래 글을 클릭하면 확인할 수 있다.
JPA를 구동하기 위해 먼저 해야할 일
먼저 JPA를 구동하기 위해서는 EntityManagerFactory를 만들어야 한다. EntityManagerFactory는 EntityManager 객체를 만들어주는 공장이다.
- Persistence.xml(Persistence class가 있음)에서 설정 정보를 조회한다.
- Persistence.xml의 설정정보를 조회해서 EntityManagerFactory를 만든다.
- 필요할 때 마다 EntityManagerFactory에서 EntityManager를 만든다.
간단하게 JPA 구동해보기
1. Member Class를 만든다. Member Class는 간단하게 Long 타입의 id와 String 타입의 name만 가진다. 이 객체는 JPA에서 쓰일 것이기 때문에 @Entity Annotation을 달아준다. 그리고 Id에는 @Id Annotation을 달아준다. @Id Annotation의 의미는 DB에 있는 MEMBER TABLE의 PK값과 이 Annotation이 붙은 값을 매칭시켜준다는 의미로 보면 된다.
@Entity
public class Member {
@Id
private Long id;
private String name;
}
2. Main에 JPA가 동작하는지 볼 수 있도록 아래 코드를 작성한다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin(); // 트랜잭션을 시작한다.
먼저 EntityFactory와 Manager를 생성하는 코드를 작성한다. 위에서 주의해야할 부분은 createEntityManagerFactory를 만들 때 ( ) 안에 들어가는 값이다. 이 값은 persistenceUnitName을 넣어주어야 한다. persistenceUnitName으로 되어있으니, 이 값이 어떤 값인지를 확인하기 위해서는 persistence.xml에 들어가서 살펴봐야 한다.
persistence.xml로 들어가보면 persistence-unit의 이름이 "hello"로 되어있는 것을 볼 수 있다. 이 값을 위의 팩토리를 만들 때 넣어주면 된다.
try {
tx.commit();
}catch (Exception e){
tx.rollback();
}finally {
em.close();
}
emf.close();
그 후 위의 코드를 Main 함수에 작성해준다. 이유는 JPA는 Transaction 단위로 쿼리를 처리한다. 그런데 예를 들어 Transaction 전송이 실패했다면, 기록되어있던 값을 RollBack 해줘야한다. 그리고 트랜잭션 커밋이 완료되었던, 되지 않았든 간에 사용이 끝난 EntityManager와 EntityManagerFactory는 차례차례 Close를 해주어야한다.
3. DB의 MEMBER TABLE에 값을 저장해보기.
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member1 = new Member();
member1.setName("memberA");
member1.setId(1L);
em.persist(member1);
tx.commit();
}catch (Exception e){
tx.rollback();
}finally {
em.close();
}
emf.close();
}
위 코드를 작성한다. 코드의 내용은 Member 객체를 하나 생성해서 DB에 저장하는 것이다. DB에 저장은 em.persist로 할 수 있다. em.persist를 하면 @Entity + @Id 어노테이션과 매핑된 DB의 테이블에 자동으로 저장을 한다. 더 자세한 동작 방식은 뒤의 영속성 컨텍스트에서 볼 수 있다.
코드를 실행했을 때, 만약 DDL-AUTO의 VALUE가 create로 되어있다면 왼쪽에서 볼 수 있듯이 자동으로 DB에 MEMBER TABLE이 생성될 것이다. DB에 MEMBER TABLE이 생성된 이후 INSERT QUERY가 나가는 것을 알 수 있다. 만약 DDL-AUTO가 Create로 설정되어있지 않다면 DB에서 직접 위의 SQL 코드를 작성해서 테이블을 만들어줘야 한다.
실행결과를 H2 DB에서 확인할 수 있다. 확인 시, ID는 입력한대로 1, 그리고 NAME은 MEMBER A가 정상으로 들어간 것을 알 수 있다.
4. DB에서 값 조회하기 + 수정하기
현재 DB의 상태는 위에서 확인할 수 있다. 이 DB에서 PK값이 1111인 객체를 찾아와서 출력하고, 멤버의 이름을 "memberKKKK"로 바꾸는 동작을 진행하고자 한다. 코드는 아래와 같이 작성했다.
Member findMember = em.find(Member.class, 1111L);
System.out.println("findMember = " + findMember);
findMember.setName("memberKKKK");
tx.commit();
실행결과를 하나씩 살펴보면 다음과 같다.
가장 먼저 JPA는 DB에서 MEMBER 객체 중 PK값이 1인 객체를 찾아오는 Select 쿼리를 보낸다. JPA는 SELECT 쿼리를 통해서 DB에 저장된 값을 메모리 상 객체에 저장했다. 이후 값을 setName() 메서드로 수정하기만 했는데, 트랜잭션 커밋 시점에 Update 쿼리가 나가는 것을 확인할 수 있다. 아래의 실행결과를 살펴보면 INSERT 쿼리 없이 update 쿼리만으로 원하는 동작이 완료된 것을 볼 수 있다.
JPA는 내부적으로 위와 같이 동작한다고 한다. 오히려 객체 입장에서는 값을 수정하고 따로 저장하지 않는 것이 굉장히 자연스럽다. 예를 들어 우리가 Member의 이름을 바꾼다고 하면, 그냥 set 메서드로 수정만 해주지 이후에 어떤 액션을 취하지 않기 때문이다.
5. DB에서 데이터 지우기
Member findMember = em.find(Member.class, 1L);
em.remove(findMember);
tx.commit();
DB에서 데이터를 지우기 위해서는 먼저 DB에서 객체를 찾아와야한다. 그리고 그 객체를 EntityManager에게 던져주면 DB에서 자동으로 지워진다. 위의 코드를 작성한 후에, 실행 결과를 보면 아래와 같다.
위의 콘솔을 살펴보면, 먼저 Select를 통해서 Member 객체를 하나 찾아온다. Member 객체를 찾아온 다음 멤버를 지우는데, 이 때 Delete 쿼리가 나가는 것을 볼 수 있다.
실제 실행 결과를 살펴보면 왼쪽에 ID 1번이 삭제된 것을 오른쪽에서 볼 수 있다.
추가 내용
JPA의 검색 쿼리
JPA는 검색을 할 때 테이블이 아닌 객체를 검색한다. 테이블을 검색하는 것 자체가 JPA의 사상을 깨뜨리는 것이기 때문이다. 그렇다고 JPA가 모든 DB 테이블을 개체로 변환해서 검색하는 것은 불가능하다. 어플리케이션이 필요한 데이터만 DB에서 불러오기 위해서는 검색 조건이 포함된 SQL이 나가게 된다.
JPA의 DB 저장
try {
Member member = new Member();
em.persist(member);
tx.commit();
}catch (Exception e){
System.out.println("this");
tx.rollback();
}finally {
em.close();
}
JPA를 통해 DB에 저장하려고 할 때, @Id를 가진 필드 값이 null이면 DB에 저장쿼리가 나가지 않는다. 중간에 exception이 뜨게 되면서 Catch쪽으로 빠지게 되는 것을 확인할 수 있다. 위 코드를 실행하고 콘솔창을 보면 결과는 아래와 같다. 단, PK값을 제외한 나머지 값은 null값이어도 DB에 저장이 되는 것 같다.
JPA의 기초지식 + 알아봐야할 내용
- 엔티티 매니저 팩토리는 딱 하나만 생성한다. 그리고 어플리케이션 전체에서 공유해서 사용한다. (왜?)
- 엔티티 매니저는 쓰레드 간에 공유하지 않는다. 사용하고 버린다.
- 엔티티는 무엇인가?
- 엔티티 매니저 팩토리를 통해서 고객의 요청이 올 때 마다 엔티티 매니저를 생상한다. 엔티티 매니저는 내부적으로 DB 커넥션을 통해서 DB를 사용한다. 엔티티 매니저를 하나 준다는 것은 데이터베이스 커넥션을 하나 받은 것이라고 생각하면 된다.
JPA의 모든 데이터 변경은 트랜잭션 안에서 실행되어야만 한다.
'Spring > JPA' 카테고리의 다른 글
다대일 연관 관계, 외래키는 어디에 있어야할까? (0) | 2021.11.27 |
---|---|
JPA의 연관관계 맵핑 (0) | 2021.11.25 |
JPA의 프록시 관련 정리 (0) | 2021.11.22 |
영속성 컨텍스트 관련 정리 (0) | 2021.11.20 |
JPA, Maven으로 Project 생성하기 (1) | 2021.11.20 |