Framework/Spring

인프런 스프링 입문 강의 #JPA

MINGYUM 2021. 2. 2. 08:33

JPA란? : (Java Persistence API) ORM(Object Relational Mapping)의 기술 표준, 인터페이스의 모음이다. ORM에 대한 자바 API의 규격이며 Hiberate, OpenJAP등이 JPA의 구현체이다. 데이터베이스를 객체지향적으로 관리할 수 있다. 

implementation 'org.springframework.boot:spring_boot-starter-data-jpa'

build.gradle에 다음 코드를 추가해주고

spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.show-sql=true 
spring.jpa.hibernate.ddl-auto=none

application.properties에 다음 코드를 써준다. application.properties는 sources 디렉토리 안에 있다. 

 

그 다음으로,

JPA 객체를 매핑해줘야하는데, 그 전에 먼저 클래스와 테이블을 매핑해야한다. 

 

1. @Entity : 클래스를 테이블과 매핑한다고 JPA에게 알려준다. 이 어노테이션이 사용되는 클래스를 엔티티 클래스라고 한다. 

2. @Table : 엔티티 클래스에 매핑될 테이블 정보를 알려준다. (name 속성으로 테이블을 설정) 이를 생략하면 클래스이름으로 매핑됨.

3. @Id : 엔티티 클래스의 PK에 매핑한다. 즉, 이 어노테이션이 사용된 필드를 식별자 필드라고 한다. 

4. @Column : 필드를 컬럼에 매핑한다. (name 속성을 사용)

5. @Generated Value : 주키의 자동 생성 전력, 즉 인덱스 자동증가 역할을 한다. @Id @GeneratedValue(strategy=GenerationType.AUTO)로 작성하는 경우에!

 

 

* show-sql : JPA가 생성하는 SQL을 출력한다. 

* ddl-auto : JPA는 테이블을 자동으로 생성하는 기능을 제공 -> create를 사용하면 엔티티 정보를 바탕으로 테이블을 자동 생성해준다 WOW

 

JPA 엔티티 매핑

: Entity어노테이션이 붙은 클래스의 각 개체와 테이블 간의 연간관계를 형성하는 것을 말한다. 

 

> import javax.persistence.Entity 관련 에러 해결

더보기

persistence에서 빨간 줄 에러가 떠서 JPA환경설정이 안되었음을 알고 javax.persistence 관련 환경설정을 다시 해주었다. 

먼저 제일 기본적인 build.gradle의 dependencies와 source>application.properties 파일을 다음과 같이 설정해주었다. 

1. build.gradle

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

 2. application.properties

spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none

이렇게 설정해줬는데도 계속 persistence에서 에러가 뜨길래 구글링구글링. 해답은 jar파일에 있는 것 같았다. 

mvnrepository.com/artifact/javax.persistence/javax.persistence-api/2.2

 

Maven Repository: javax.persistence » javax.persistence-api » 2.2

javax.persistence javax.persistence-api 2.2 // https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api compile group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2' // https://mvnrepository.com/artifact/javax.persiste

mvnrepository.com

여기서 javax.persistence-api-2.2.jar 파일을 다운로드 받아서 다음과 같이 Project Structure>Modules에 Export 파일에 추가해주었다. (servlet-app.jar은 javax 관련 모듈을 추가해준다고 하여 삽질하다가 추가시킨 파일인데 왜 이 jar 파일로는 해결이 안되었는지 의문. 아마 Persistence 관련 인터페이스가 없었기때문이 아닐까..?)

아무튼 이렇게 했더니 Persistence는 해결이 되었다. 근데 main>hello.hellospring>domain>Member.java에서 import해 준 Entity는 빨간 줄 에러가 뜨는 것을 확인할 수 있었다. 또 다시 멘붕이 와서 이리저리 하다가

다음과 같이 main 패키지 안에서 jar파일을 추가하여 해결할 수 있었다. 아따리 어렵다 ~^^..

 

암튼 domain>Member.java에서 만들어 준 Memer 클래스를 매핑해주기 위해 클래스 위에 @Entity 어노테이션을 추가해준다.

package hello.hellospring.domain;
import javax.persistence.*;


@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name){
        this.name = name;
    }
}

 

그리고 @Id 어노테이션으로 id필드를 PK로 설정해준다. (id필드는 식별자 필드가 됨)

@GeneratedValue(startegy = GenerationType.IDENTITY) 코드는 테이블에 데이터가 추가될 때마다 PK가 자동 증가하도록 설정하기 위해 작성한다. 

 

이렇게 매핑을 완료하고 repository폴더에 JpaMemberRepository 파일을 생성해 MemberRepsitory 인터페이스의 구현체를 만들자.

 

package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import javax.persistence.*;
import java.util.List;
import java.util.Optional;

public class JpaMemberRepository implements MemberRepository{

    private final EntityManager em; //DB와의 통신을 처리. JPA를 쓸려면 Entity Manger을 주입받아야 함.

    public JpaMemberRepository(EntityManager em) {
        this.em = em;
    }

    @Override
    public Member save(Member member) {
        em.persist(member);
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        Member member = em.find(Member.class, id); 
        return Optional.ofNullable(member); // 값이 없을 수도 있으므로
    }

    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result   = em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name",name)
                .getResultList();

        return result.stream().findAny();
        //객체지향 쿼리 사용
    }

    @Override
    public List<Member> findAll() {
        return em.createQuery("select m from Member as m", Member.class)
                .getResultList();
    }
}

EntityManager JPA 기술로 DB와의 통신을 처리하기 위해 필수적으로 주입해야하는 인터페이스이다. 

save 메소드에서 em.persist()로 엔티티를 저장하고, Optional<Member> findById(Long id)와 Optional<Member>findByName(String name)을 에서 엔티티를 조회하고 쿼리를 생성한다. 

- em.find(데이터 타입, 식별자) 로 엔티티 조회

- em.createQuery(쿼리문, 데이터 타입)으로 

- stream() : 

 

- Optional<T> 클래스는 T타입의 객체를 포장해주는 Wrapper 클래스이다. Null Pointer Exception 예외를 회피할 수 있다. Optional <Member>findById는 Member 데이터 타입의 메소드를 형성해주되 null 값이 리턴되면 예외 처리가 이루어진다. 

 

- List<T> 클래스는 T타입의 List를 만들어 관리하는 역할을 한다. List<Member> findAll() 메소드를 형성해주면 return 값에 의해서 Member 엔티티에서 m 칼럼을 가져와  getResultList메서드를 통해 결과를 컬렉션으로 반환한다. 

* 컬렉션 인터페이스란, 여러 원소들을 담을 수 있는 자료구조를 뜻한다. 

 

> 자바의 자료구조 유형은 어떤게 있나요?

더보기

- 순서가 있는 목록인 List형
- 순서가 중요하지 않은 목록인 Set형
- 먼저 들어온 것이 먼저 나가는 Queue형
- KEY-VALUE의 형태로 저장되는 Map형

출처: https://www.crocus.co.kr/1553 [Crocus]

여기까지가 JpaMemberRepository에 대한 설명이다. 

 

 

스프링 데이터 JPA

- 인터페이스를 통한 기본적인 CRUD 구현

- 페이징 기능 제공

+ 동적 쿼리 Querydsl 라이브러리 사용해서 쿼리도 자바 코드로 안전하게 작성할 수 있다.