도입
지난 시간에 JPA 프로젝트를 설정하는 방법에 대하여 알아보았습니다. 이번시간에는 JPA로 CRUD를 하는 것을 알아보도록 하겠습니다. CRUD는 Create, Read, Update, Delete의 약자로 생성, 읽기, 갱신, 삭제를 의미합니다. 이번 포스팅에서는 DB에 데이터를 넣고, 조회하고, 수정하고, 삭제하는 방법을 알아보도록 하겠습니다.
시작 전에 JPA?
객체지향적인 언어와 RDB는 구현할 때 굉장히 모순적인 부분이 많습니다. 객체들이 협력하며 만들어낸 결과물들을 DB에 저장을 할 때는 객체가 아닌 테이블에 저장이 되기 때문에 테이블로 각각 데이터를 넣어주어야하는 번거로움이 있습니다. 이로써 객체지향적으로 프로그램을 개발하여도 RDB와 연동시켜주는 과정에서 굉장히 적은 생산성을 보여주었습니다. 이를 해결하기 위해 나온 기술이 ORM이며 현재 자바 진영의 표준 ORM이 JPA가 됩니다.
이를 사용하여 객체를 테이블에 넣어주어야하는 번거로운 노가다를 안해도 되며 객체 자체를 컬렉션 쓰듯이 DB에 넣어주고 빼주는 역할을 수행할 수 있게 됩니다.
Entity Manager
Entity Manager는 엔티티를 관리해주는 역할을 수행합니다.
엔티티를 저장하고, 삭제하고, 생성하고, 수정하는 역할을 수행해줍니다.
Entity Manager는 다른 쓰레드들과 공유를해서는 절대 안됩니다.(동시성 문제 때문에)
EntityManager em = emf.createEntityManager();
위 코드는 EntityManager 를 생성하는 방법입니다. emf는 Entity Manager Factory를 의미합니다.
Entity Manager Factory
Entity Manager Factory는 Entity Manager를 생성해주는 역할을 수행하며 DB 한개당 한개씩 매칭이 됩니다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
위 코드는 hello라는 DB를 관리하는 매니저를 생산하는 팩토리를 구한 것 입니다.
트랜젝션
트랜젝션은 명령의 덩어리라고 생각하면 됩니다. DB에 접근할 때 명령들을 묶어서 한번에 실행시켜줍니다.
만약 철수가 은행에서 영희계좌로 1000원을 이체한다고 하겠습니다. 그 로직은 다음과 같다고 가정하겠습니다.
1.철수 계좌에서 -1000
2.영희 계좌로 +1000
3.각 계좌에 저장
근데 동시에 영희 어머니가 영희에게 용돈으로 10000원을 보내주었습니다. 그 로직이 다음과 같다고 가정하겠습니다.
1.영희 어머니 계좌 -10000
2.영희 계좌 +10000
3. 각 계좌의 저장
만약 두 일이 동시에 발생하게 된다면, 철수의 명령 1번이 수행 된 후 철수의 명령 2번이 아닌 영희어머니의 명령 1번이 실행될 수도 있게 됩니다. 즉 프로그램의 실행에 있어 신뢰성을 잃게됩니다. 만약 위 동작이 "철수 1번 -> 엄마 1번 -> 엄마 2번 -> 철수 2번"으로 실행되었다면 최종적으로 영희의 계좌에 +11000이라는 돈이 들어올 보장이 없습니다. 프로그램이 여러 쓰레드가 동시적으로 돌아가는 상황에서 이러한 Race Condition을 방지하기 위하여 DB에서는 트랜젝션이라 하여 명령들을 묶어 원자성으로 실행하게 됩니다.
JPA의 모든 Entity관련 명령은 트랜젝션으로 실행됩니다.
EntityTransaction tx = em.getTransaction();
tx.begin();
// 명령
tx.commit();
트랜젝션은 Entity Manager에서 생성할 수 있으며, begin()과 commit()사이의 코드를 원자적으로 실행해줍니다. 만약 문제가 생긴다면 rollback()을 시켜 되돌려주면 됩니다. Spring Boot를 사용하게되면 이러한 과정을 직접 해주기 때문에 따로 구현할 필요는 없어집니다.
JPA로 CRUD 구현하기
객체를 DB에 넣고, 조회하고, 변경하고, 지우는 과정을 알아보도록 하겠습니다. JPA를 수행할 때 유의할 점은 트렌젝션 단위로 실행을 해 주어야 한다는 것 입니다. 그리고 생성한 Entity Manager는 반드시 close로 없애주어야 합니다. (다른 스레드에서 사용하지 못하도록)
Entity 추가하기
JPA는 ORM이기 때문에 객체를 엔티티로 추가하여 줍니다.
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@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 void setName(String name){
this.name = name;
}
public String getName() {
return name;
}
}
Member라는 Class를 정의하여 Entity를 생성하였습니다. 해당 클래스가 Entity라고 표시해주기 위해 @Entity annotation이 붙어 있습니다. 그리고 Member라는 엔티티에 저장된 값들의 키값을 표현해주기 위해 id가 있어야합니다.
C : Create (추가하기)
DB에 추가하기 위해서 persist()를 사용하여줍니다.
tx.begin();
try {
Member member = new Member();
member.setId(1L);
member.setName("hello");
em.persist(member);
tx.commit();
}
catch (Exception e){
tx.rollback();
}
finally {
em.close();
}
try & catch를 사용하는 이유는 만약 생성중에 오류가 발생하였다면 그것을 rollback시켜준 뒤 Entity Manager를 닫아주기 위함입니다.
저장을 하려고 하는 테이블과 매칭되는 객체를 생성하여준 뒤 그 객체를 persist해주면 저장이 됩니다. 위에서 보듯이 모든 과정은 트랜젝션 안에서 수행되는 것을 알 수 있습니다.
R : Read(조회하기)
tx.begin();
try {
em.find(Member.class,1L);
tx.commit();
}
catch (Exception e){
tx.rollback();
}
finally {
em.close();
}
단건을 조회하는 방법은 이렇게 find를 사용하여 찾고자하는 Entity의 class와 그 값의 ID를 넣어주면 값을 조회할 수 있습니다.
단건이 아닌 여러건을 조회하는 방법은 jpql을 사용하여 처리할 수있으며 추후 다시 포스팅하겠습니다.
U : Update(변경하기)
변경이 매우 특이하게 동작을 합니다. 단순하게 저장된 객체를 가져와서 변경만 해주면 알아서 체크하고 변경하게 됩니다.
x.begin();
try {
Member findMember = em.find(Member.class, 1L);
findMember.setName("hello");
tx.commit();
}
catch (Exception e){
tx.rollback();
}
finally {
em.close();
}
emf.close();
이렇게 위해서 setName으로 이름을 변경하면 dirty checking을 수행하며 엔티티의 값중 변경된 값을 찾아 변경해주게 됩니다.
D : Delete(삭제하기)
삭제는 remove()를 사용하여 해결할 수 있습니다.
tx.begin();
try {
Member findMember = em.find(Member.class, 1L);
em.remove(findMember);
tx.commit();
}
catch (Exception e){
tx.rollback();
}
finally {
em.close();
}
emf.close();
이 글은 김영한님의 강의 "자바 ORM 표준 JPA 프로그래밍"를 공부한 후 작성한 글 입니다.
'Back-end > JPA' 카테고리의 다른 글
JPA 기본 키 매핑하기 (0) | 2022.01.12 |
---|---|
JPA로 필드와 칼럼 매핑하는 annotation 알아보기 (0) | 2022.01.10 |
JPA로 객체와 테이블 매핑하기 (0) | 2022.01.07 |
JPA 영속성 컨텍스트란? (0) | 2022.01.03 |
JPA 프로젝트 설정(Maven, H2 DB) (0) | 2021.12.30 |