본문 바로가기

SpringFramework/JPA

JPA - 기본 개념 및 내용정리

ORM(Object-Relational-Mapping)이란?

: 객체와 관계형 데이터베이스(RDBMS)의 데이터를 자동으로 연결해 주는 것을 말한다. 객체 - 관계 매핑을 통해 프로그램의 복잡도를 줄이고(트랜잭션 처리 등) 작업을 더 편리하게 할 수 있도록 돕는다.

- ORM은 객체지향 패러다임을 관계형 데이터베이스에 보존하는 기술이다.

- 객체지향의 구조가 관계형 데이터베이스와 유사하다는 점에서 시작되며, 객체지향을 자동으로 관계형 데이터베이스에 맞게 처리해주는 기법에 대해서 아이디어를 내기 시작했고 그것이 ORM의 개념이 자리잡는 시작점이였다.

- SQL Query가 아닌, 메소드의 call을 통해 데이터를 제어할 수 있다.

 

- ORM의 장점

1] 비즈니스 로직에 더 집중할 수 있다.

2] 재사용(생산성) 및 유지보수가 용이하다

    객체지향적으로 데이터를 관리할 수 있기 때문에, 전체 프로그램 구조를 일관되게 유지할 수 있음

    객체만으로 동작하기 때문에, 코드만으로도 쉽게 유지보수가 진행.

    스키마 변경이 일어나도 대응에 많은 유지보수(코드에 손대는)가 필요로 하지 않음.

3] DBMS에 대한 종속성이 줄어든다.

    DBMS가 변경되더라도 코드, 쿼리, 구현법, 자료형 등을 변경하지 않아도 대응가능 (그런데, 한번 정해진 DBMS가 변경되는 경우는 그렇게 많이 없을듯..)

 

- ORM의 단점

1] 접근자체는 어렵지않지만, 장점을 살리려면 초기 학습이 필요하다.

2] 복잡한 쿼리 로직에 대한 대응이 어렵다.

    통계쿼리나, 정규화를 통한 테이블간의 이해관계가 복잡할때, 설계가 잘못되어있는 경우..?

3] 프로시저가 많은 서비스에서는 ORM의 객체 지향적인 부분을 사용하는 것이 어렵다.

JPA(Java Persistence API)

JPA의 흐름

JPA는, 위에서 소개했던 자바 ORM 기술에 대한 표준 명세로, JAVA에서 제공하는 API이다. Hibernate는 JPA라는 명세의 구현체이다. 마치 자바의 인터페이스(Hibernate)와 그 인터페이스를 구현(JPA)한 느낌이다.

(= SpringDataJPA는  Hibernate를 스프링 부트에서 쉽게 사용할 수 있는 추가적인 API들을 제공함)

따라서, JPA를 사용하기 위해서 반드시 Hibernate를 사용할 필요가 없다는 것이다. 다른 인터페이스를 implements하여 사용해도 되기 때문이다. (ex) DataNucleus, EclipseLink 등..). 하지만 Hibernate를 implements하는 이유는 이게 굉장히 잘되어있는 라이브러리이기 때문이다.

 

- 왜 JPA를 사용해야 할까?

1] 생산성

: JPA를 사용하면 INSERT SQL작성, JDBC API 호출 등의 반복적인 코드를 JPA가 대신 처리해줌. 이런 것들은 데이터베이스 설계 중심에서 객체 설계 중심으로 패러다임이 바뀔 수 있다.

 

2] 유지보수

: 데이터베이스에 신규 필드 및 필드정보 변경이 일어나게 된다면 CRUD SQL 및 Mapping하는 JDBC API 코드를 모두 수정해야 한다. 그러나 JPA를 사용한다면 이런 과정을 JPA가 대신 처리해준다. 결국 개발자는 유지보수할 코드 수가 줄어든다.

 

3] 성능

: JPA는 애플리케이션과 데이터베이스 사이에서 동작하고 그 사이에서 다양한 성능 최적화의 임무를 수행한다.

String userId = "1234500";
User user1 = jpa.find(userId);
User user2 = jpa.find(userId);

이 코드는 같은 트랜잭션 안에서 같은 회원을 두번 조회하는 코드이다. JDBC API를 사용해서 해당 코드를 직접 작성했다면, 데이터베이스와 통신을 2번 진행했을 것이다. 하지만 JPA를 사용한다면, 첫번째 호출은 데이터베이스와 통신하지만, 두번째 호출은 User 객체를 재사용한다. 단편적인 예제이지만, 실제 운영서비스라면 성능차이는 꽤나 많이 벌어질 것이다.

 

4] 데이터 접근 추상화와 벤더 독립성

: RDMS는 같은 기능도 Vendor(oracle, mysql, H2 ..)마다 사용법이 다른 경우가 많다.

벤더 독립성

JPA는 애플리케이션과 데이터베이스 사이에 추상화된 데이터 접근 계층을 제공해서 애플리케이션이 특정 데이터베이스에 종속되지 않도록 해준다. 데이터베이스를 변경하게 되더라도 사용변경처리만 적용하면 된다.

 

5] ORM 표준

: JPA는 자바 진영의 ORM 기술 표준이다. 표준을 사용하면 다른 구현 기술로 손쉽게 변경이 가능하다.

Entity클래스와 JPA Repository

개발에 필요한 것은 두종류의 코드만 있으면 된다.

1] JPA를 통해서 관리하게 되는 객체 - Entity객체

(더 자세한 내용은 아래의 링크를 통해 확인한다)

https://xggames.tistory.com/44

 

package com.ys.test.lab.api.entity;

import javax.persistence.*;

@Entity
@Table(name = "user")
public class UserEntity {
    @Id
    @Column(name = "user_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;

    private String name;

    private int age;
}

예제코드를 통해 Entity객체를 살펴보자.

 

- UserEntity라는 class를 정의하였다.

- @Entity : 이 클래스를 테이블과 매핑한다고 명시한다. 이 어노테이션이 선언된 클래스를 엔티티 클래스라고 한다. JPA에서 관리한다

- @Table : 엔티티 클래스에 매핑할 테이블 정보를 알려준다. 이 어노테이션이 생략되면, 클래스 이름을 테이블 이름으로 매핑한다.

- @Id : 엔티티 클래스의 필드를 테이블의 기본키(PK)에 매핑한다. 식별자 필드

    - 키(key)생성 전략

        AUTO(default): JPA 구현체(스프링 부트에서는 Hibernate)가 생성 방식을 결정(JPA에게 위임한다)

        IDENTITY: 사용하는 데이터베이스가 키 생성을 결정한다. MySQL이나 MariaDB는 Auto-Increment 방식을 사용한다

        SEQUENCE: 데이터베이스의 sequence를 이용해서 key를 생성한다. @SequenceGenerator와 함께 사용

        (참고문서: https://dololak.tistory.com/479)

        TABLE : 키 생성 전용 테이블을 생성하여 키생성. @TableGenerator와 함께 사용

- @Column : 필드를 컬럼에 매핑한다. (nullable, name, length 등을 이용해서 데이터베이스 칼럼에 필요한 정보를 제공)

 

2] Entity객체들을 처리하는 기능을 가진 Repository

    (더 자세한 내용은 아래의 링크를 통해 확인한다)

    https://xggames.tistory.com/53

    - JPA에서 제공하는 인터페이스로 설계

    - Repository에서 인터페이스를 하나를 제공하는 것으로 사용할 수 있다.

package com.ys.test.lab.api.repository;

import com.ys.test.lab.api.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<UserEntity, Long> {
    // 준비끝!
}

- @Repository 어노테이션 선언을 별도로 해줄 필요가 없다. JpaRepository를 상속받으면 자동으로 Bean에 등록된다.

- 실제 동작시에는 스프링이 내부적으로 해당 인터페이스에 맞는 코드를 생성하는 방식을 이용

method 설명
save() 데이터 저장
findOne() pk로 row 한건 찾기
findAll() 전체 row 조회. sort, paging 사용 가능
count() 데이터 row count
delete() 데이터 삭제

위의 기본기능을 제외한 조회 기능을 추가하고 싶으면 규칙에 맞는 메서드를 추가하면 된다.

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) public interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") v

docs.spring.io

ex) User findByUserId(Long userId); (user_id를 통해 해당되는 row를 찾아서 User Entity로 리턴)

 

3] Spring Data JPA를 위한 스프링부트 설정

- spring.jpa.generate-ddl: 프로젝트 실행시 데이터베이스 초기화를 사용할 것인지를 결정 (default: false)

보통 실무에서는 DBA가 관리하거나 DB Tool에서 정의하는 경우가 많아서 운영환경에서는 사용하지 않고, Local환경에서는 개발하면서 편리할 것으로 생각됨. 그렇지만 쓰지말자. 새로 DDL을 정의하는 행위이므로, 데이터가 다 날아갈 수도 있는 참극이 벌어질 수 있다

 

- spring.jpa.hibernate.ddl-auto: 프로젝트 실행시에 데이터베이스 초기화전략을 결정

    none: 사용하지 않는다 (사실상 무효옵션)

    create: 어플리케이션 시작시, 기존테이블 삭제 후 다시생성

    update: 변경된 스키마만 반영 (운영DB에서는 사용하지 않는다)

    create-drop: 어플리케이션 시작, 종료시점 모두 삭제한다

    validate: 변경된 스키마가 있는지 확인만 해준다. 변경이 있다면 어플리케이션은 종료된다

 

- spring.jpa.show-sql: JPA처리시에 발생하는 SQL을 출력할 것인지를 결정

- spring.jpa.properties.hibernate.format_sql: hibernate에서 실행하는 SQL을 보기좋게 출력

참고자료

Spring 공식문서: https://docs.spring.io/spring-data/jpa/docs/2.4.3/reference/html/#repositories.definition

서적 - 자바 ORM 표준 JPA 프로그래밍 - 김영한 지음

'SpringFramework > JPA' 카테고리의 다른 글

JPA - 값타입  (0) 2021.11.16
JPA - 연관관계 고급매핑  (0) 2021.11.15
JPA - 연관관계  (0) 2021.11.14
JPA - 엔티티 매핑  (0) 2021.11.12
JPA - 영속성 컨텍스트  (0) 2021.11.03