inblog logo
|
👨🏻‍💻DriedPollack's Blog
    🌼Spring

    [스프링 부트 쇼핑몰 프로젝트 with JPA] 2장 정리

    엔티티 매니저를 통해 영속성 컨텍스트에 접근하여 데이터베이스 작업을 수행하며, 이는 1차 캐시, 동일성 보장, 쓰기 지연, 변경 감지 등의 이점을 제공한다. Spring Data JPA를 사용하면 Repository 인터페이스를 통해 엔티티를 관리할 수 있으며, 복잡한 쿼리는 @Query 어노테이션과 JPQL을 사용하거나 Querydsl을 사용하여 처리할 수 있다. 또한, 쇼핑몰 프로젝트를 생성하고 상품 엔티티를 설계하는 방법, 데이터베이스 초기화 전략, 엔티티 매칭 관련 어노테이션, 기본키 생성 전략 등에 대해 설명하였다.
    DriedPollack's avatar
    DriedPollack
    Mar 29, 2024
    [스프링 부트 쇼핑몰 프로젝트 with JPA] 2장 정리
    Contents
    🌼JPA💡핵심 키워드🌼쇼핑몰 스포젝트 생성하기💡핵심 키워드🌼상품 엔티티 설계하기💡핵심 키워드🌼Repository 설계하기💡핵심 키워드🌼쿼리 메소드💡핵심 키워드🌼Repository 설계하기💡핵심 키워드🌼Spring DATA JPA @Query 어노테이션💡핵심 키워드🌼Spring DATA JPA Querydsl💡핵심 키워드🏁결론

    🌼JPA

    💡핵심 키워드

    • JPA(Java Persistence API)는 자바 ORM 기술에 대한 API 표준이다. ORM이란 Object Relational Mapping의 약자로 객체와 관계형 데이터베이스를 매핑해주는 것을 말한다.

    JPA란?

    • 데이터를 관계형 데이터베이스에서 관리하기 위해 우리는 SQL문을 사용한다.
      • SQL 중심 개발의 문제점은 개발자가 CRUD문을 작성해서 객체를 관계형 데이터베이스에 넣어주고 가져오는 작업을 하는 것이다.
      • 즉 자바 객체를 SQL을 통해 데이터베이스에 관리하게 하고 데이터베이스에 저장된 데이터를 자바 어플리케이션에서 사용하려면 SQL을 통해 다시 자바 객체로 변환하는 반복적인 작업을 해야 한다.
      • 또한 객체와 관계형 데이터베이스의 패러다임의 불일치가 발생한다.
    • JPA 사용시 장점
      • 특정 데이터베이스에 종속되지 않는다.
      • 객체지향적 프로그래밍이 가능하다.
      • 생산성을 향상시킬 수 있다.
    • JPA 사용시 단점
      • 복잡한 쿼리를 사용할 경우 SQL문을 사용하는 게 나을 수 있다.
      • 성능 저하의 위험이 존재한다.
      • 학습 시간이 오래 걸린다.

    JPA 동작 방식

    • 엔티티란 데이터베이스의 테이블에 대응하는 클래스다.
      • @Entity가 붙은 클래스는 JPA에서 관리하는 엔티티가 된다.
    • 엔티티 매니저 팩토리는 엔티티 매니저 인스턴스를 관리하는 주체이다.
      • 애플리케이션 실행 시 한 개만 만들어지며 사용자로부터 요청이 오면 엔티티 매니저 팩토리로부터 엔티티 매니저를 생성한다.
    • 엔티티 매니저는 영속성 컨텍스트에 접근하여 엔티티에 대한 데이터베이스 작업을 제공한다.
      • 내부적으로 데이터베이스 커넥션을 사용해서 데이터베이스에 접근한다.
      • find() : 영속성 컨텍스트에서 엔티티를 검색하고 영속성 컨텍스트에 없을 경우 데이터베이스에서 데이터를 찾아 영속성 컨텍스트에 저장한다.
      • persist() : 엔티티를 영속성 컨텍스트에 저장한다.
      • remove() : 엔티티 클래스를 영속성 컨텍스트에서 삭제한다.
      • flush() :영속성 컨텍스트에 저장된 내용을 데이터베이스에 반영한다.
    • 영속성 컨텍스트는 엔티티를 영구 저장하는 환경으로 엔티티 매니저를 통해 접근한다.
      • 생명주기
        내용
        비영속(new)
        new 키워드를 통해 생성된 상태로 영속성 컨텍스트와 관련이 없는 상태
        영속(managed)
        -엔티티가 영속성 컨텍스트에 저장된 상태로 영속성 컨텍스트에 의해 관리되는 상태 -영속 상태에서 데이터베이스에 저장되지 않으며, 트랜잭션 커밋 시점에 데이터베이스에 반영
        준영속 상태(detached)
        영속성 컨텍스트에 엔티티가 저장되었다가 분리된 상태
        삭제 상태(removed)
        영속성 컨텍스트와 데이터베이스에서 삭제된 상태
    • 영속성 컨텍스트 사용시 이점은 다음과 같다.
      • 1차 캐시
        • 영속성 컨텍스트에는 1차 캐시가 존재하며 Map<KEY, VALUE>로 저장된다.
        • entityManager.find() 메소드 호출시 영속성 컨텍스트의 1차 캐시를 조회해서 엔티티가 존재할 경우 반환하고, 없으면 데이터베이스에서 조회 후 1차 캐시에 저장 및 리턴한다.
      • 동일성 보장
        • 하나의 트랜잭션에서 같은 키값으로 영속성 컨텍스트에 저장된 엔티티 조회 시 1차 캐시에 저장된 엔티티를 조회하므로 같은 엔티티 조회를 보장한다.
      • 트랜잭션을 지원하는 쓰기 지연
        • 영속성 컨텍스트에는 쓰기 지연 SQL 저장소가 존재한다.
        • entityManager.persist()를 호출하면 1차 캐시에 저장되는 것과 동시에 쓰기 지연 SQL 저장소에 SQL문이 저장된다.
        • 이렇게 SQL문을 쌓아두고 트랜잭션을 커밋하는 시점에 저장된 SQL문들이 flush되면서 데이터베이스에 반영된다. 따라서 성능에서 이점을 볼 수 있다.
      • 변경 감지
        • JPA는 1차 캐시에 데이터베이스에서 처음 불러온 엔티티의 스냅샷 값을 갖고 있다.
        • 그리고 1차 캐시에 저장된 엔티티와 스냅샷을 비교 후 변경 내용이 있다면 UPDATE SQL문을 쓰기 지연 SQL 저장소에 담아둔다.
        • 그리고 데이터베이스에 커밋 시점에 변경 내용을 자동으로 반영한다. 즉, 따로 update문을 호출할 필요가 없다.
     

    🌼쇼핑몰 스포젝트 생성하기

    💡핵심 키워드

    프로젝트 생성하기

    • Thymeleaf : 서버에서 가공한 데이터를 뷰에 보여주기 위한 템플릿 엔진이다.
    • Spring Data JPA : JPA를 쉽세 구현할 수 있도록 도와주는 모듈이다.
    • MySQL Driver : MySQL 데이터베이스를 사용하기 위한 의존성이다.
    • H2 Dataabase : 자바 기반의 관계형 데이터베이스로 매우 가볍고 빠른 데이터베이스다. 메모리 내에 데이터를 저장하는 메모리 데이터베이스 기능을 지원한다.

    데이터베이스 초기화 전략

    • application.properties에 추가한 jpa 옵션 중 주의 깊게 봐야 할 설정은 DDL AUTO 옵션이다.
      • spring.jpa.hibernate.ddl-auto 옵션을 통해 애플리케이션 구동 시 JPA의 데이터베이스 초기화 전략을 설정할 수 있다.
        • none : 사용하지 않음
        • create : 기존 테이블 삭제 후 테이블 생성
        • create-drop : 기존 테이블 삭제 후 테이블 생성, 종료 시점에 테이블 삭제
        • update : 변경된 스키마 적용
        • validate : 엔티티와 테이블 정상 매핑 확인
      • 스테이징, 운영환경에서는 절대로 create ,create-drop, update 를 사용하면 안된다.
     

    🌼상품 엔티티 설계하기

    💡핵심 키워드

    • 쇼핑몰을 만들기 위해서는 상품 등록 및 조회, 수정, 삭제가 가능해야 한다.

    상품 엔티티 설계하기

    • 엔티티란 데이터베이스의 테이블에 대응하는 클래스다.
      • @Entity가 붙은 클래스는 JPA에서 관리하며 엔티티라고 한다.
    • Lombok의 어노테이션을 이용한다면 getter, setter, toString등을 자동으로 만들어주기 때문에 코드를 깔끔하게 짤 수 있다.
    • 엔티티 매칭 관련 어노테이션
      • 어노테이션
        설명
        @Entity
        클래스를 엔티티로 선언
        @Table
        엔티티와 매핑할 테이블을 지정
        @id
        테이블의 기본키에 사용할 속성을 지정
        @GeneratedValue
        키 값을 생성하는 전략 명시
        @Column
        필드와 컬럼 매핑
        @Lob
        BLOB, CLOB 타입 매핑
        @CreationTimestamp
        insert 시 시간 자동 저장
        @UpdateTimeStamp
        update 시 시간 자동 저장
        @Enumeratierd
        enum 타입 매핑
        @Transient
        해당 필드 데이터베이스 매핑 무시
        @Temporal
        날짜 타입 매핑
        @CreateDate
        엔티티가 생성되어 저장될 때 시간 자동 저장
        @LastModifiedDate
        조회한 엔티티의 값을 변경할 떄 시간 자동 저장
    • @Column 어노테이션 추가 속성
      • 속성
        설명
        기본값
        name
        필드와 매핑할 컬럼의 이름 설정
        객체의 필드 이름
        unique(DDL)
        유니크 제약 조건
        ㅤ
        insertable
        insert 가능 여부
        true
        updatable
        update 가능 여부
        true
        length
        String 타입의 문자 길이 제약조건 설정
        255
        nullable(DDL)
        null 값의 허용 어부 설정, false 설정 시 DDL 생성 시에 not null 제약조건 추가
        ㅤ
        columnDefinition
        데이터베이스 컬럼 정보 직접 기술 예) @Column(columnDefinition = “varchar(5) default’10’ not null”)
        ㅤ
        precision, scale(DDL)
        BigDecimal 타입에서 사용(BigInteger 가능) precision은 소수점을 포함한 전체 자리수이고, scale은 소수점 자리수. Double 타입과 float 타입에는 적용되지 않음
        ㅤ
    • @GeneratedValue 어노테이션을 통한 기본키를 생성하는 전략
      • 생성 전략
        설명
        GenerationType.AUTO(default)
        JPA 구현체가 자동으로 생성 전략 결정
        GenerationType.IDENTITY
        기본키 생성을 데이터베이스에 위임 예) MySql 데이터베이스의 경우 AUTO_INCREMENT를 사용하여 기본키 생성
        GenerationType.SEQUENCE
        데이터베이스 시퀀스 오브젝트를 이용한 기본키 생성 @SequenceGenerator를 사용하여 시퀀스 등록 필요
        GenerationType.TABLE
        키 생성용 테이블 사용, @TableGenerator 필요
     

    🌼Repository 설계하기

    💡핵심 키워드

    • Spring Data JPA에서는 엔티티 매니저를 직접 이용해 코드를 작성하지 않아도 된다.
      • 그 대신 Data Access Object의 역할을 하는 Repository 인터페이스를 설계한 후 사용하는 것만으로 충분하다.
    • JpaRepository에서 지원하는 메소드 예시
      • 메소드
        기능
        <S extends T> save(S entity)
        엔티티 저장 및 수정
        boid delete(T entity)
        엔티티 삭제
        count()
        엔티티 총 개수 반환
        Iterable<T> findAll()
        모든 엔티티 조회
    • 테스트 환경의 경우 h2 데이터베이스를 사용하도록 resources 아래에 테스트 환경을 위한 별도의 application-test.properties 파일을 만든다.
     

    🌼쿼리 메소드

    💡핵심 키워드

    • 쿼리 메소드는 스프링 데이터 JPA에서 제공하는 핵심 기능 중 하나로 Repository 인터페이스에 간단한 네이밍 룰을 이용하여 메소드를 작성하면 원하는 쿼리를 실행할 수 있다.
    • 쿼리 메소드를 이용할 떄 가장 많이 사용하는 문법으로 find를 사용한다. 엔티티의 이름은 생략이 가능하며, By 뒤에는 검색할 때 사용할 변수의 이름을 적어준다.
      • find + (엔티티 이름) + By + 변수이름
    • 쿼리 메소드 Sample 및 JPQL snippet
      • Keyword
        Sample
        JPQL snippet
        And
        findByLastnameAndFirstname
        … where x.lastname = ?1 and x.firstname = 2?
        Or
        findByLastnameOrFirstname
        … where x.lastname = ?1 or x.firstname = 2?
        Is, Equals
        findByFirstname findByFirstnameIS findByFirstnameEquals
        … where x.lastname = ?1
        Between
        findByStartDateBetween
        … where x.startDate between ?1 and ?2
        LessThan
        findByAgeLessThan
        … where x.age < ?1
        LessThanEqual
        findByAgeLessThanEqual
        … where x.age <= ?1
        GraterThan
        findByAgeGraterThan
        … where x.age > ?1
        GraterThanEqual
        findByAgeGraterThanEqual
        … where x.age >= ?1
        After
        findByStartDateAfter
        … where x.startDate > ?1
        Before
        findByStartDateBefore
        … where x.startDate < ?1
        IsNull, Null IsNotNull
        findByAge(Is)Null
        … where x.age is null
        NotNull
        findByAge(Is)NotNull
        … where x.age not null
        Like
        FindByFirstnameLike
        … where x.firstname like ?1
        NotLike
        FindByFirstnameNotLike
        … where x.firstname not like ?1
        StartingWith
        FindByFirstnameStartingWith
        … where x.firstname like ?1 (parameter bound with appended %)
        EndingWith
        FindByFirstnameEndingWIth
        … where x.firstname like ?1 (parameter bound with prepended %)
        Containing
        FindByFirstnameContaining
        … where x.firstname like ?1 (parameter bound with wrapped in %)
        OrderBy
        findByAgeOrderByLastnameDesc
        … where x.age = ?1 order by x.lastname desc
        Not
        findByLastnameNot
        … where x.lastname <> ?1
        In
        findByAgeIn(Collection<Age> ages)
        … where x.age in ?1
        NotIn
        findByAgeNotIn(Collection<Age> ages)
        … where x.age not in ?1
        True
        findByActiveTrue()
        … where x.active = true
        False
        findByActiveFalse()
        … where x.active = false
        IgnoreCase
        findByFirstnameIgnoreCase
        … where UPPER(x.firstname) = UPPER(?1)
     

    🌼Repository 설계하기

    💡핵심 키워드

    • Spring Data JPA에서는 엔티티 매니저를 직접 이용해 코드를 작성하지 않아도 된다.
      • 그 대신 Data Access Object의 역할을 하는 Repository 인터페이스를 설계한 후 사용하는 것만으로 충분하다.
    • JpaRepository에서 지원하는 메소드 예시
      • 메소드
        기능
        <S extends T> save(S entity)
        엔티티 저장 및 수정
        boid delete(T entity)
        엔티티 삭제
        count()
        엔티티 총 개수 반환
        Iterable<T> findAll()
        모든 엔티티 조회
    • 테스트 환경의 경우 h2 데이터베이스를 사용하도록 resources 아래에 테스트 환경을 위한 별도의 application-test.properties 파일을 만든다.
     

    🌼Spring DATA JPA @Query 어노테이션

    💡핵심 키워드

    • 조건이 많아질 때 쿼리 메소드를 선언하면 이름이 너무 길어진다. 따라서 쿼리 메소드는 복잡한 쿼리를 다루기에 적합하지 않다.
    • Spring Data JPA에서 제공하는 @Query 어노테이션을 이용하면 SQL과 유사한 JPQL이라는 객체지향 쿼리 언어를 통해 복잡한 쿼리도 처리가 가능하다.
      • JPQL은 SQL을 추상화해서 사용하기 떄문에 특정 데이터베이스 SQL에 의존하지 않는다.
    • @Param 어노테이션을 이용하여 변수를 JPQL에 전달하는 대신 파라미터의 순서를 이용해 전달해줄 수 있다.
      • 이 경우 :파라미터 이름 대신 철 번째 파라미터를 전달하겠다는 ?1 이라는 표현을 사용하면 된다.
     

    🌼Spring DATA JPA Querydsl

    💡핵심 키워드

    • @Query 어노테이션 안에 JPQL 문법으로 문자열을 입력할 때 잘못 입력하면 컴파일 시점에 에러를 발견할 수 없다.
      • 이를 보완할 수 있는 방법으로 Querydsl이 있다.
    • Querydsl 장점
      • 고정된 SQL문이 아닌 조건에 맞게 동적으로 쿼리를 생성할 수 있다.
      • 비슷한 쿼리를 재사용할 수 있으며 제약 조건 조립 및 가독성을 향상시킬 수 있다.
      • 문자열이 아닌 자바 소스코드로 작성하기 때문에 컴파일 시점에 오류를 발견할 수 있다.
      • IDE의 도움을 받아서 자동 완성 기능을 이용할 수 있기 때문에 생산성을 향상시킬 수 있다.
    • Querydsl을 사용하기 위해서는 pom.xml 파일의 <dependencies> </dependencies> 사이에 querydsl-jpa 의존성과 querydsl-apt 의존성을 추가해야 한다. 이 경우 version은 5.0.0 이상이어야 한다.
    • 추가한 의존성을 받아오기 위해 인텔리제이의 오른쪽에 있는 Maven에서 Reload All Maven Projects 버튼을 클릭한다.
      • 이후 maven compile을 통해 QItem 클래스를 생성할 수 있다.
    • JPAQuery 데이터 반환 메소드
      • 메소드
        기능
        List<T> fetch()
        조회 결과 리스트 반환
        T fetchOne
        조회 대상이 1건인 경우 제네릭으로 지정한 타입 반환
        T fetchFirst()
        조회 대상 중 1건만 반환
        Long fetchCount()
        조회 대상 개수 반환
        QueryResult<T> fetchResults()
        조회한 리스트와 전체 개수를 포함한 QueryResults 반환
    • QueryDslPredicateExecutor 인터페이스 정의 메소드
      • 메소드
        기능
        long count(Predicate)
        조건에 맞는 데이터의 총 개수 반환
        boolean exists(Predicate)
        조건에 맞는 데이터 존재 여부 반환
        Iterable findAll(Predicate)
        조건에 맞는 모든 데이터 반환
        Page<T> findAll(Predicate, Pageable)
        조건에 맞는 페이지 데이터 반환
        Iterable findAll(Predicate, Sort)
        조건에 맞는 정렬된 데이터 반환
        T findOne(Predicate)
        조건에 맞는 데이터 1개 반환
     

    🏁결론

    해당 내용을 정리하면서 JPA의 등장 배경 및 특징, JPA의 구조와 동작 방식, SpringData JPA를 이용하여 데이터를 처리하는 방법을 이해할 수 있었다.
    Share article
    Contents
    🌼JPA💡핵심 키워드🌼쇼핑몰 스포젝트 생성하기💡핵심 키워드🌼상품 엔티티 설계하기💡핵심 키워드🌼Repository 설계하기💡핵심 키워드🌼쿼리 메소드💡핵심 키워드🌼Repository 설계하기💡핵심 키워드🌼Spring DATA JPA @Query 어노테이션💡핵심 키워드🌼Spring DATA JPA Querydsl💡핵심 키워드🏁결론

    👨🏻‍💻DriedPollack's Blog

    RSS·Powered by Inblog