[JPA] 설정, 기본 실습

설정

 JPA 실습을 위해서 실습용 DB를 설치하고, 프로젝트의 pom.xml에 라이브러리를 추가해준다.

spring.io

spring.io사이트에 들어가서 확인해보면 실습을 진행할 스프링부트 2.6.2버전에서는 hibernate 5.6.3.Final을 사용함을 알 수 있다. 여기서 하이버네이트란 JPA의 구현체로, JPA '인터페이스'를 구현한다. JPA는 단순히 hibernate를 추상화한 인터페이스일뿐, JPA자체로만 동작하지 않는다. 따라서 스프링부트와 호환되는 hibernate버전을 의존관계에 추가해주자)

//pom.xml 일부
<dependencies> 
 	<dependency> 
		 <groupId>org.hibernate</groupId> 
 		<artifactId>hibernate-core</artifactId> 
		 <version>5.6.3.Final</version> //스프링부트 버전에 맞춘 하이버네이트 버전
 	</dependency> 
 	...
	 <dependency> 
 		<groupId>com.h2database</groupId> 
 		<artifactId>h2</artifactId> 
 		<version>2.0.204</version> //사용중인 h2DB version
	 </dependency>
</dependencies>

다음으로 JPA 설정파일을 추가하자. JPA설정파일은 res/META-INF/persistence.xml에 설정파일을 추가하면 된다.

//persistence.xml 일부
 <persistence-unit name="hello"> //jpa db 이름
 	<properties> 
    	//DB 접근정보 (h2 console에서 입력정보)
 		<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호환(문자, 함수, 페이징 쿼리 등등)을 위한 hibernate전용 옵션
 		<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"/> 
 	</properties>
...

시작

EntitymanagerFactory emf = Persistence.createEntityManagerFactory("persistenceUnitName"); // 엔티티매니저 팩토리 반환
Entitymanager em = emf.createEntityManager(); //팩토리에서 엔티티매니저 호출

//추가적인 code작성

//application 종료
em.close();
emf.close();

EntitymanagerFactory : 애플리케이션 로딩 시점에 단 하나만 생성

Entitymanager : 트랜잭션 단위(db connection)마다 생성

 

@Entity : JPA가 관리할 객체
@Id: 데이터베이스 PK mapping
@Entity //JPA에게 관리해야할 테이블임을 인식
public class Member { 
 @Id 
 private Long id; 
 private String name; 
 //Getter, Setter … 
}

-PK(primary key, 기본키)란?
 : 테이블 생성시 정의되며, 관계형 DB에서 테이블에서 항목의 주민등록번호라고 생각하면 쉽다. 기본키는 다른 항목과 절대로 중복되어 나타날 수 없는 단일 값을 가지며, 절대로 null값을 가질 수 없다. 테이블을 기본키를 하나까지만 가질 수 있다.

-FK(foreign key, 외래키)란?
: 다른 테이블의 PK를 참조하는 키. 테이블 생성시 정의되며, FK가 정의된 테이블은 자식 테이블이고, 참조되는 미리 생성되어있던 테이블을 부모 테이블이라고 한다. 부모 테이블의 참조되는 칼럼에 존재하는 값만을 입력할 수 있다.

그럼 이제 생성한 객체DTO를 jpa를 이용해서 테이블에 추가시켜보자

//entitymanager에서 트랜잭션 얻어오고 시작
EntityTransaction tx = em.getTransaction();
tx.begin();

//멤버 추가
Member member = new Member();
member.setId(1L);
member.setName("HelloA");
em.persist(member);

tx.commit();

INSERT sql쿼리문 없이도 테이블에 추가되는것을 확인할 수 있다. JPA가 매핑정보만 보고 알아서 테이블에 추가시켜준것이다. 그런데 위의 코드에는 @Entity만 지정해주었을뿐 어떤 테이블명에 저장하라는 정보는 설정해준 적이 없다. 이는 관례상 jpa가 클래스명과 동일한 테이블에 저장해주기 때문이다. 만약 다른 테이블에 저장하기를 원한다면

@Entity
@Table(name = "customname") //customname이라는 테이블에 추가
public class Member {
...

과 같이 @Table을 이용하여 설정을 추가시킬 수 있다.

 

주의

- 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유

- 엔티티 매니저는 thread간 공유X

- JPA의 모든 데이터 변경은 트랜잭션 안에서만 진행

 

 

코드 전문

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        
        try {
            Member member = new Member();
            member.setId(1L);
            member.setName("HelloA");
            //삽입
            em.persist(member);
            
            //조회, 수정
            Member findmember = em.find(Member.class, 1L);
            findMember.setName("HelloB");
            //em.persist(findMember) >>>>>>>>> 필요X(setName메소드만 호출해줘도 쿼리문이 나간다)
            
            //삭제
            em.remove(member);

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}

예외처리구문을 통해서 에러가 발생하면 rollback();을 통해 엔티티매니저를 닫아주는 예외처리문까지 구현할 수 있다.

이제 여기다가 스프링까지 적용시키면 실무에서는 이러한 복잡한 사용없이 em.persist(member);정도의 호출만 필요로 할 것이다.

신기한점은 수정하고 setter메소드만 호출해주고 persist를 해주지 않아도 쿼리문이 나간다는 점이다. 이는 jpa가 commit시점에 상태를 체크하여 자동으로 UPDATE를 해주기 때문이다.