Entity
DB에 member라는 테이블이 있고, 해당 테이블의 스키마가 다음과 같다고 해보자.
create table Member (
id bigint not null,
name varchar(255),
primary key(id)
);
그렇다면 엔티티는 다음과 같이 만들 수 있다. 엔티티는 JPA가 관리할 객체이며, DB의 테이블과 매핑된다.
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class Member {
@Id
private Long id;
private String name;
//Getter, Setter ...
}
기본적으로 JPA는 모든 필드를 불러오게 끔 구현되어 있다. 하지만, 모든 케이스에서 id, name 필드를 전부 다 다루지 않을 수 있다. 이 경우에는 id 필드만 다루는 경우도 있을 수 있다. 그런 경우를 대비해서 엔티티 클래스를 하나 더 만들 수 있다.
따라서 테이블은 한 개지만, 엔티티는 경우에 따라서 여러 개를 만들 수 있다고도 한다.
EntityManagerFactory 생성
JPA를 시작하려면 우선 persistence.xml의 설정 정보를 사용해서 엔티티 매니저 팩토리를 생성해야 한다. 이때 Persistence 클래스를 사용한다. 이 클래스는 엔티티매니저팩토리를 생성해서 JPA를 사용할 수 있게 해 준다.
//factory는 애플리케이션 로딩 시점에 딱 한번 만들어야 됨.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //persistence-unit에서 지정함 이름을 넘긴다.
EntityManager em = emf.createEntityManager(); //엔티티 매니저 하나 받음 ( 마치 자바 컬렉션이라고 생각 ( 내 객체를 대신 저장해주는 ))
이렇게 하면 META-INF/persistence.xml에서 이름이 hello인 영속성 유닛(persistence-unit)을 찾아서 엔티티매니저팩토리를 생성한다. 아래는 persistence.xml 파일의 일부이다. 빌드 시스템을 gradle로 할 경우 src/main/resources/META-INF 폴더를 만들어 persistence.xml 파일을 만들고 아래 내용으로 설정을 해주면 된다. 그리고 엔티티를 class로 명시해 주어야 하다.
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
<persistence-unit name="hello">
<class>Member</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value="비밀번호를 입력해주세요"/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
<!--현재 사용할 데이터베이스의 방언을 선택한다. 이 부분만 바꾸면 자바코드를 바꾸지 않아도 다른 회사의 DB를 쓸 수 있다.-->
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<!--옵션, 이지만 JPA가 어떤 SQL을 만들어내는지 보고 싶으면 넣자.-->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
</properties>
</persistence-unit>
</persistence>
그리고 maven 프로젝트로 할 경우 댜음과 같이 설정해 주면 된다.
<persistence-unit name="hello"> <!-- 이름이 hello인 영속성 유닛 -->
<properties>
<!-- 필수 속성 -->
<!--데이터베이스 접근 정보-->
<property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="jakarta.persistence.jdbc.user" value="sa"/>
<property name="jakarta.persistence.jdbc.password" value=""/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<!-- 옵션 -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
</persistence-unit>
즉 이렇듯, gradle 시스템에서나, maven 빌드 시스템에서나 JPA는 persistencexml을 통해 필요한 설정 정보를 관리한다.persistence.xml의 정보를 읽어서 JPA를 동작시키기 위한 객체를 만들고 JPA 구현체에 따라서는 커넥션 풀도 생성해야 하기 때문에 엔티티 매니저를 생성하는 비용은 매우 크다. 따라서 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유해야 한다.
EntityManager 생성
엔티티매니저팩토리를 생성했다면, 이를 이용해서 엔티티 매니저를 생성해야 한다.
엔티티 매니저를 이용해서 엔티티를 데이터베이스에 등록/수정/삭제/조회할 수 있다. 따라서 JPA의 대부분의 기능은 엔티티 매니저가 제공한다고 볼 수 있다.
엔티티 매니저는 내부의 데이터베이스 커넥션을 유지하면서 데이터베이스와 통신한다. 따라서 스레드 간에 공유하거나 재사용하면 안 된다. ( 사용하고 버려야 한다. )
import jakarta.persistence.*;
public class JpaMain {
public static void main(String[] args) {
//factory는 애플리케이션 로딩 시점에 딱 한번 만들어야 됨.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //persistence-unit에서 지정함 이름을 넘긴다.
EntityManager em = emf.createEntityManager(); //엔티티 매니저 하나 받음 ( 마치 자바 컬렉션이라고 생각 ( 내 객체를 대신 저장해주는 ))
//code
EntityTransaction tx = em.getTransaction(); //트랜잭션 API
tx.begin(); //트랜잭션 시작
try {
//비즈니스 로직
Member member = new Member();
member.setId(2L);
member.setName("HelloB");
em.persist(member);
tx.commit(); //트랜잭션 커밋
} catch (Exception e) {
tx.rollback(); //예외 발생 시 트랜잭션 롤백
} finally {
em.close(); //엔티티 매니저 종료
}
emf.close(); //엔티티 매니저 팩토리 종료
}
}
비즈니스 로직을 보면 엔티티매니저를 통해서 수행되는 것을 알 수 있다.
저장
//비즈니스 로직
Member member = new Member();
member.setId(2L);
member.setName("HelloB");
em.persist(member);
엔티티를 저장하려면, 엔티티 매니저의 persist() 메서드에 저장할 엔티티를 넘겨주면 된다. 위의 코드는 member 엔티티를 생성하고, em.persist(member)를 실행해 엔티티를 저장한다. JPA는 회원 엔티티의 매핑정보를 분석해서 SQL을 만들어 데이터베이스에 전달한다.
INSERT INTO MEMBER (ID, NAME) VALUES ('2L','HelloB')
수정
Member findMember = em.find(Member.class, 2L);
findMember.setName("nameB");
JPA는 어떤 엔티티가 변경되었는지 추적하는 기능을 갖추고 있다. 따라서 member.setName()처럼 엔티티의 값을 변경하면 알아서 UPDATE 쿼리를 작성해서 데이터베이스에 값을 반영한다.
삭제
em.remove(findMember);
엔티티를 삭제할 때는 엔티티 매니저의 remove() 메서드에 삭제하려는 엔티티를 넘겨주면 된다. 그러면 DELETE 쿼리를 생성해서 실행한다.
한건 조회
Member findMember = em.find(Member.class, 2L);
find() 메서드는 조회할 엔티티 타입과, @Id로 데이터베이스 테이블의 기본키와 매핑한 식별자 값으로 엔티티 하나를 조회하는 메서드이다. 이 메서드를 사용하면 SELECT 쿼리를 생성해서 데이터베이스에 결과를 조회한다. 그리고 조회한 값으로 엔티티를 생성해서 반환한다.
종료
마지막으로 사용이 끝난 엔티티 매니저는 꼭 종료해주어야 한다.
그리고 그다음으로 애플리케이션을 종료할 때 엔티티 매니저 팩토리도 다음처럼 종료해야 한다.
em.close();
emf.close();
정리
엔티티 매니저 팩토리의 특징
* 엔티티 매니저를 만드는 역할을 수행한다.
* 생성 비용이 크다
* 하나의 프로젝트 내에서 한개만 만들어서 사용한다. ( 하나의 어플리케이션에서 하나 생성 후 공유 )
* 여러 스레드가 동시에 접근해도 안전하게 설계
엔티티 매니저의 특징
* 생성 비용이 적다.
* 여러 스레드가 동시에 접근하면 동시성 문제가 발생한다. -> 엔티티 매니저 팩토리와는 달리 공유하지 않는다.
* DB 커넥션 풀에서 연결이 꼭 필요한 시점에 커넥션을 얻어서 사용한다. ( 사용자 요청에 의해 트랜잭션을 시작할 때 )
Reference
[1] 인프런 김영한 님의 강의 - https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
자바 ORM 표준 JPA 프로그래밍 - 기본편 | 김영한 - 인프런
김영한 | JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 실무에서도
www.inflearn.com
[2] 김영한 - 자바 ORM 표준 JPA 프로그래밍
[3] https://jays-lab.tistory.com/35
JPA 엔티티 매니저 팩토리와 엔티티 매니저, 영속성 컨텍스트
엔티티 매니저 팩토리와 엔티티 매니저 엔티티 매니저는 엔티티를 저장, 수정, 삭제, 조회등 엔티티와 관련된 모든 일을 처리. 엔티티 매니저 팩토리를 생성하는 코드. EntityManagerFactory emf = Persist
jays-lab.tistory.com
[4] https://psvm.kr/posts/tutorials/jpa/2-start-jpa-with-gradle
JPA 프로젝트 Gradle로 시작하기
IntelliJ 커뮤니티 버전을 사용해 JPA 5 버전 프로젝트를 Gradle로 설정하자.
psvm.kr
'JPA' 카테고리의 다른 글
[JPA] 영속성 관리, 영속성 컨텍스트 (0) | 2024.05.03 |
---|---|
[JPA] 데이터베이스 방언, Dialect (0) | 2024.05.03 |