본문 바로가기
BackEnd/java spring

JPA 구동 방식과 애플리케이션 만들어보기

by kkkdh 2023. 1. 20.
728x90

JPA 공부를 위한 프로젝트 생성 정보

DB: h2 database

build tool: Maven

Java: version 11

pom.xml을 이용한 라이브러리 추가
persistence.xml을 이용한 JPA 설정

pom.xml을 이용해 라이브러리를 추가하고, persistence.xml는 JPA 설정 파일에 해당한다.

  • /META-INF/persistence.xml 위치에 설정 파일을 저장한다.
  • persistence-unit name으로 이름을 지정
  • javax-persistence: JPA 표준 속성을 의미
  • hibernate: 하이버네이트 전용 속성을 의미(하이버네이트는 JPA 구현체중 하나)

property 태그를 이용해 속성 정보를 하나하나 지정하는 것 같다.

  • user: sa
  • password: 없음
  • url: jdbc:h2:tcp://localhost/~/test
  • dialect는 방언으로 어떤 RDBMS의 sql을 사용할 것인지를 지정한다고 보면 된다. (여기서는 h2 dialect를 사용)

 

데이터베이스 방언

dialect를 사용하는 방식은 위와 같다

  • JPA는 특정 데이터베이스에 종속되지 않는다.
  • 각각의 데이터베이스가 제공하는 SQL 문법과  함수는 조금씩 다르다.
    • 가변 문자: MySQL은 varchar, Oracle은 varchar2를 사용
    • 문자열 자르는 함수: MySQL은 substring(), Oracle은 substr()
    • 페이징: MySQL은 LIMIT, Oracle은 ROWNUM
  • 방언은 SQL 표준을 지키지 않는 특정 데이터베이스만의 고유 기능을 의미한다.

hibernate는 40가지 이상의 데이터베이스 방언을 지원하기 때문에, 현업에서 사용하는 대부분의 데이터베이스의 방언을 지원한다고 볼 수 있다.

 

따라서 다양한 database로의 전환이 쉽게 가능함


JPA의 구동 방식

JPA는 다음과 같은 방식으로 동작한다.

  1. Persistence 객체가 persistence.xml 파일을 확인해서, 설정 정보를 조회한다.
  2. 이를 이용해 Persistence 객체가 EntityManagerFactory 클래스를 생성한다.
  3. 생성된 EntityManagerFactory가 필요할 때마다 EntityManager를 생성

실습을 위한 코드

위 코드와 같이 Persistence 클래스에서 createEntityManagerFactory method를 이용해 이전에 "hello"라고 지정한 persistenceUnit의 EntityManagerFactory를 생성한다.

 

이후 EntityManagerFactory를 이용해 필요할 때 EntityManager를 생성할 수 있고, 사용 후에는 EntityManager를 close 한다.

 

애플리케이션 종료 시에는 EntityManagerFactory도 close method를 호출해 종료시켜야 한다.


JPA를 이용해 간단한 예제를 만들어보자

DB connection을 얻어 query를 보내고 종료하는 일관적인 단위의 작업을 수행할 때마다 EntityManager를 꼭 만들어줘야 한다고 함

우선 Member table을 만들고 객체를 만들어보자.

DB에 table을 만들고, 객체를 생성한 다음 아래의 예시코드를 수행해 보면

될 것 같았는데, 오류가 발생한다.

이것은 JPA에서는 transaction이란 단위가 매우 중요하기 때문, JPA에서 모든 데이터를 변경하고 조회하는 작업은 꼭 transaction 안에서 작업을 해야 한다.

 

그래서 이렇게 고쳐줘야 한다.

EntityManager를 이용해 transaction을 생성한다

transaction의 begin method와 commit method를 이용해, 일련의 과정이 transaction 안에서 발생하도록 변경해 준다.

insert query가 실행됨을 콘솔 창에서 확인할 수 있다.
H2 database에도 저장됨을 확인 가능

위와 같이 실행된 sql문이 보이는 것은 hibernate.show_sql 속성을 true로 설정했기 때문이다. (persistence.xml 파일에서)

 

이렇게 query문을 직접 작성하지 않고, 매핑만 해줘도 JPA가 알아서 해주는 편리한 결과를 확인할 수 있다.

 

그런데, 어떻게 어느 테이블인지 지정도 안 하고, 테이블의 어떤 속성에 어떤 필드의 값이 들어갈지 설정도 안 했는데 잘 들어간 거지?? -> JPA의 관습 덕분이라고 한다.

 

지금은 객체의 필드 명과 테이블의 속성 이름이 같아서 자동으로 매핑된 경우이고

다른 이름을 갖는 경우라면, 어노테이션을 이용해서 직접 매핑시킬 수도 있다고 한다.

@Entity
@Table(name = "Member")
public class Member{

    @Id
    private Long id;
    
    @Column(name = "username")
    private String name;
    
    ...
}

이런 식으로 직접 이름을 매핑할 수도 있다.

 

코드를 조금 리팩토링 하면 다음과 같이 바꿔줄 수 있다.

try, catch 구문으로 문제 상황을 잡아줘야 한다.

원래 상태의 코드는 중간에서 문제가 발생할 시에 EntityManager와 EntityManagerFactory를 제대로 닫아주지 못했다.

 

그래서 try, catch 구문을 추가해 문제가 발생해도 transaction을 rollback 하고, connection이 제대로 닫힐 수 있도록 코드를 수정한 개념 (훨씬 안정적이다)

 

사실 위의 코드는 정석으로 JPA만 사용한 경우이고, 실제로 사용할 때는 Spring과 함께 사용하기 때문에, em.persist만 사용하면, 나머지 코드는 알아서 실행해 준다고 함

 

조회 기능은 find method를 이용해 간단히 구현 가능

위와 같이 아주 간단하게 조회 기능도 구현이 가능하다. (EntityManger 객체의 find method만 사용하면 끝)

조회 결과

수정이 가장 야무지다. 

수정은 그냥 find로 객체를 찾은 다음에 setter로 수정하고, persist 하면 되겠지..??

→ persist 할 필요도 없음!

setter로 필드를 수정만 하니까 변경을 감지하고 알아서 update query를 보내준다.

위 결과처럼 JPA가 transaction을 commit 하기 직전에 변경 사항을 감지해서 udpate query를 직접 보내준다.

DB에도 변경됨

이는 JPA를 통해서 entity를 가져오면, 이걸 JPA에서 관리해 주기 때문이라고 한다.

 

주의할 점

  • EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에서 공유한다!
  • EntityManager는 thread 간에 공유하지 않는다. (사용하고 버려야)
  • JPA의 모든 데이터 변경은 transaction 안에서 실행한다.
    • 모든 DB가 내부적으로 transaction 단위로 일을 처리하기 때문
    • 우리가 단건 query로 DB를 변경하는 것도 내부적으로는 transaction으로 처리된다고 함

JPQL

EntityManager로 식별자를 이용해 간단하게 entity를 조회하는 방법도 있지만,

 

만약 "나이가 18살 이상인 회원을 모두 검색하자!!" 같은 작업을 처리하고 싶다면??

 

이럴 때, JPQL이라는 것을 사용한다고 한다.

  • JPA를 사용하면, entity 객체를 중심으로 개발
  • 문제는 검색 쿼리이다.
  • 검색을 할 때에도 테이블이 아닌 entity 객체를 대상으로 검색하게 된다.
    • 테이블에서 가져오면, JPA의 사상이 깨짐
  • 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
  • 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국에는 검색 조건이 포함된 SQL이 필요

이러한 이유로 테이블이 아닌 entity 객체를 대상으로 query를 짤 수 있는 문법이 들어간 것이고, 이것이 JPA에서 제공하는 JPQL이다.

  • JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다!
  • SQL과 문법이 유사하며, 기본적으로 select, from, where, group by, having, join을 모두 지원
  • JPQL은 entity 객체를 대상으로 쿼리
  • SQL은 db table을 대상으로 쿼리

이렇게 JPQL을 사용하면, DB에 의존적이지 않게 될 수 있다. (DBMS를 바꿔도 똑같이 동작 가능하다)

 

이후 챕터에서 더 자세하게 다뤄보자

728x90

'BackEnd > java spring' 카테고리의 다른 글

[JPA] 엔티티 매핑  (0) 2023.01.27
[JPA] 영속성 컨텍스트에 대한 정리  (0) 2023.01.21
[JPA] Java 표준 ORM인 JPA란?  (0) 2023.01.19
[Spring] 빈 스코프 알아보기  (0) 2023.01.07
[Spring] 빈 생명주기 콜백  (0) 2023.01.06

댓글