새싹🌱

[JAVA/Spring] JPA

idleday 2022. 11. 19. 00:00

Spring Data JPA

JPA (Java Persistence API)

ORM(Object-Relational Mapping) 기술 표준으로 사용되는 자바 인터페이스 모음

  • 장점: 유지보수 용이, DBMS 종속성X
  • 단점: 복잡하고 학습 어려움
  • JPA Hibernate (오픈소스)
  • JPA vs MyBatis (sequelize vs MySQL)

[Spring Boot] MySQL & JPA 연동 및 테스트

프로젝트에 의존성 추가

  • build.gradle에 추가 후 build
  • implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'mysql:mysql-connector-java'

application.properties 설정에 DB 정보 추가

server.address=localhost
server.port=8080 

# MySQL 설정
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# DB Source URL
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sesac?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8&serverTimezone=Asia/Seoul
spring.datasource.username=~~~
spring.datasource.password=~~~

# mysql 연동
spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

#true 설정시 JPA 쿼리문 확인 가능
spring.jpa.show-sql=true

# JPA의 구현체인 Hibernate가 동작하면서 발생한 SQL의 가독성을 높여준다.
spring.jpa.properties.hibernate.format_sql=true

# DDL(Create, Alter, Drop) 정의시 DB의 고유 기능을 사용할 수 있다.
**spring.jpa.hibernate.ddl-auto=**create

데이터베이스 스키마 자동 생성 기능

  • 클래스의 매핑 정보와 데이터베이스 방언을 사용하여 데이터베이스 스키마 생성
  • 어플리케이션 실행 시점에 데이터베이스 테이블 자동 생성
  • application.properties 에 속성 추가
  • spring.jpa.hibernate.ddl-auto 속성
    • create : 기존 테이블 삭제하고 새로 생성 [ DROP + CREATE ]
    • create-drop : create 속성 + 어플리케이션 종료할 때 생성한 DDL 제거 [ DROP + CREATE + DROP ]
    • update : DB 테이블과 엔티티(domain 패키지 파일) 매핑 정보를 비교하고 변경사항만 수정 [ ALTER + CREATE ]
    • none : 자동 생성 기능을 사용하지 않음

Error

JPA Hibernate 엔티티(Entity) 매핑

/* **Hibernate Entity** : domain 패키지 내 파일 */

@Getter 
@Builder // 객체 생성
@AllArgsConstructor
@NoArgsConstructor

@Table(name = "tbl_memo")
@Entity
public class Memo {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) //MySQL의 AUTO_INCREMENT를 사용
    private Long id;
 
    @Column(length = 200, nullable = false)
    private String memoText;
 
}

Entity 매핑 annotation

  • @Entity ❗
    • DB 테이블과의 매핑
    • @Entity가 붙은 클래스는 JPA가 관리
    • 속성
      • Name : PA에서 사용할 엔티티 이름을 지정한다. (보통 default값인 클래스 이름을 사용)
    • 주의사항
      • 기본 생성자 필수 (JPA가 엔티티 객체 생성 시 기본 생성자를 사용하기 때문)
      • final 클래스, enum, interface, inner class 에는 사용할 수 없다.
      • 저장할 필드에 final 사용 불가
  • **@Table**
    • 엔티티와 매핑할 테이블 지정 (클래스 명과 같은 경우 생략 가능)
    • 생략 시 매핑한 엔티티 이름을 테이블 이름으로 사용
    • 속성
      • Name  : 매핑할 테이블 이름 (default. 엔티티 이름 사용)
      • CataLog  : catalog 기능이 있는 DB에서 catalog 를 매핑 (default. DB 명)
      • Schema  : schema 기능이 있는 DB에서 schema를 매핑
      • uniqueConstraints : DDL 생성 시 유니크 제약조건을 만듦 스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용
  • **@Getter**
  • **@Id**
  • **@GeneratedValue**  PK 생성 전략
    • 직접 할당
      • em.persist() 호출 전 어플리케이션에서 직접 식별자 값 할당
    • 자동 생성
      • GenerationType.**IDENTITY**  기본키 생성을 DB에 위임 (AUTO_INCREMENT)
      • GenerationType.**SEQUENCE**  DB SEQUENCE를 이용해서 키 생성 + @SequenceGenerator
      • GenerationType.**TABLE**  키 생성 전용 테이블 사용 + @TableGenerator
      • GenerationType.**AUTO**(default)  JPA 구현체(Hibernate)가 생성 방식 결정
        • 오라클 → SEQUENCE , MySQL→ IDENTITY
  • **@Column**
    • 객체 필드를 DB Column에 매핑
    • 속성
      • name  : 필드와 매핑할 테이블 컬럼 이름 (default: 객체의 필드 이름)
      • nullable (DDL) : null 값 허용 여부 (default: true)
      • unique (DDL) : 유일값 제약조건
      • columnDefinition (DDL) : 컬럼 정보
      • Length (DDL) : 문자 길이 제약조건, String 타입에만 사용 (default: 255)
      • percision , scale (DDL) : BigDemical, BigInteger 타입에서 사용

  • @Transient
    • 필드 매핑X
    • 데이터베이스에 저장하지 않고 조회하지도 않는다.
    • 객체에 임시로 어떤 값을 보관하고 싶을 때 사용
  • 타입매핑 @Enumerated @Temporal @Lob
  • 연관관계 매핑 @ManyToOne @JoinColumn

JPA Repository 생성

JpaRepositry


Hibernate(JPA 구현체)를 이용하기 위해 Spring Data JPA가 제공하는 API 중 가장 많이 사용되는 인터페이스

/* Spring Data **JPA Repository** */

package SeSAC.spring.study.SeSACspringstudy.repository;
**import org.springframework.data.jpa.repository.JpaRepository;**
import SeSAC.spring.study.SeSACspringstudy.domain.Board;
**import java.util.Optional;**

																	// **extends JpaRepository<객체, PK타입>**
**public interface** SD_BoardRepository **extends JpaRepository<Board, Integer>** {
    
		Optional<Board> findByName(String name);

}
  • JpaRepository 상속 → SQL문 없이 CRUD 작업 가능
  • 제네릭 타입 <Entity, PK 타입> 지정 → Spring Data JPA가 자동으로 스프링의 빈(bean)으로 등록
    • [ 스프링이 내부적으로 인터페이스 타입에 맞는 객체를 생성해서 빈으로 등록 ]
/* 직접 만든 JPA Repository */

package SeSAC.spring.study.SeSACspringstudy.repository;
**import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;**
import SeSAC.spring.study.SeSACspringstudy.domain.Board;
**import javax.persistence.*;**
import java.util.*;

**@Repository
@RequiredArgsConstructor**
**public class** JPARepository **implements BoardRepository** {

    **private final EntityManager** em;

    @Override
    public Board save(Board board) {
        this.**em.persist**(board);
        return board;
    }

    @Override
    public Optional<Board> findById(int id) {
        return **Optional.empty();**
    }

    @Override
    public Optional<Board> findByName(String name) {
        return **Optional.empty();**
    }

    @Override
    public List<Board> findAll() {
        // Select * from board as b;
        return **em.createQuery**("select b from Board b", Board.class)
                .getResultList();   // List<Board>
    }
}

테스트를 통한 CRUD 기능 확인

Create

Repository 객체의 save() 메소드를 사용

@SpringBootTest
public class MemoRepositoryTest {
 
    @Autowired
    MemoRepository memoRepository;
 
    @Test
    public void InsertDummies() {
 
        IntStream.rangeClosed(1, 10).forEach(i -> {
            Memo memo = Memo.builder()
                    .memoText("Sample..." + i)
                    .build();
            //Create!
            memoRepository**.save**(memo);
        });
    }

Read

findById()

  • 해당하는 객체를 Optional 타입으로 반환
  • 한번 더 결과가 존재하는지 체크
@SpringBootTest
public class MemoRepositoryTest {
 
    @Autowired
    MemoRepository memoRepository;
 
    @Test
    public void SelectDummies() {
 
        Long id = 10L;
 
        **Optional**<Memo> result = memoRepository**.findById(**id);
 
        System.out.println("=============================");
 
        if(result.isPresent()) {
            Memo memo = result.get();
            System.out.println(memo);
        }
    }
}

Update

save()

내부적으로 해당 엔티티의 @Id값이 일치하는지를 확인해서 insert 혹은 update 작업을 처리

  • JPA는 엔티티 객체들을 메모리상에 보관하려고 하기 때문에
  • 특정한 엔티티 객체가 존재하는지 확인하는 select가 먼저 실행되고
  • 해당 @Id를 가진 엔티티 객체가 있다면 update, 그렇지 않다면 insert 실행
@SpringBootTest
public class MemoRepositoryTest {
 
    @Autowired
    MemoRepository memoRepository;
 
    @Test
    public void UpdateDummies() {
        Memo memo = Memo.builder()
                .id(10L)
                .memoText("Update Text")
                .build();
 
        memoRepository**.save**(memo);
    }

Delete

  • 수정 작업과 동일한 개념으로 삭제하려는 엔티티 객체가 있는지 먼저 확인하고, 삭제

Spring Data JPA

JPA (Java Persistence API)

ORM(Object-Relational Mapping) 기술 표준으로 사용되는 자바 인터페이스 모음

  • 장점: 유지보수 용이, DBMS 종속성X
  • 단점: 복잡하고 학습 어려움

  • JPA Hibernate (오픈소스)
  • JPA vs MyBatis (sequelize vs MySQL)

[Spring Boot] MySQL & JPA 연동 및 테스트

프로젝트에 의존성 추가

  • build.gradle에 추가 후 build
  • implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'mysql:mysql-connector-java'

application.properties 설정에 DB 정보 추가

server.address=localhost
server.port=8080 

# MySQL 설정
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# DB Source URL
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sesac?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8&serverTimezone=Asia/Seoul
spring.datasource.username=~~~
spring.datasource.password=~~~

# mysql 연동
spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

#true 설정시 JPA 쿼리문 확인 가능
spring.jpa.show-sql=true

# JPA의 구현체인 Hibernate가 동작하면서 발생한 SQL의 가독성을 높여준다.
spring.jpa.properties.hibernate.format_sql=true

# DDL(Create, Alter, Drop) 정의시 DB의 고유 기능을 사용할 수 있다.
**spring.jpa.hibernate.ddl-auto=**create

데이터베이스 스키마 자동 생성 기능

  • 클래스의 매핑 정보와 데이터베이스 방언을 사용하여 데이터베이스 스키마 생성
  • 어플리케이션 실행 시점에 데이터베이스 테이블 자동 생성
  • application.properties 에 속성 추가
  • spring.jpa.hibernate.ddl-auto 속성
    • create : 기존 테이블 삭제하고 새로 생성 [ DROP + CREATE ]
    • create-drop : create 속성 + 어플리케이션 종료할 때 생성한 DDL 제거 [ DROP + CREATE + DROP ]
    • update : DB 테이블과 엔티티(domain 패키지 파일) 매핑 정보를 비교하고 변경사항만 수정 [ ALTER + CREATE ]
    • none : 자동 생성 기능을 사용하지 않음

Error

JPA Hibernate 엔티티(Entity) 매핑

/* **Hibernate Entity** : domain 패키지 내 파일 */

@Getter 
@Builder // 객체 생성
@AllArgsConstructor
@NoArgsConstructor

@Table(name = "tbl_memo")
@Entity
public class Memo {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) //MySQL의 AUTO_INCREMENT를 사용
    private Long id;
 
    @Column(length = 200, nullable = false)
    private String memoText;
 
}

Entity 매핑 annotation

  • **@Entity** ❗
    • DB 테이블과의 매핑
    • @Entity가 붙은 클래스는 JPA가 관리
    • 속성
      • Name : PA에서 사용할 엔티티 이름을 지정한다. (보통 default값인 클래스 이름을 사용)
    • 주의사항
      • 기본 생성자 필수 (JPA가 엔티티 객체 생성 시 기본 생성자를 사용하기 때문)
      • final 클래스, enum, interface, inner class 에는 사용할 수 없다.
      • 저장할 필드에 final 사용 불가
  • **@Table**
    • 엔티티와 매핑할 테이블 지정 (클래스 명과 같은 경우 생략 가능)
    • 생략 시 매핑한 엔티티 이름을 테이블 이름으로 사용
    • 속성
      • Name  : 매핑할 테이블 이름 (default. 엔티티 이름 사용)
      • CataLog  : catalog 기능이 있는 DB에서 catalog 를 매핑 (default. DB 명)
      • Schema  : schema 기능이 있는 DB에서 schema를 매핑
      • uniqueConstraints : DDL 생성 시 유니크 제약조건을 만듦 스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용
  • **@Getter**
  • **@Id**
  • **@GeneratedValue**  PK 생성 전략
    • 직접 할당
      • em.persist() 호출 전 어플리케이션에서 직접 식별자 값 할당
    • 자동 생성
      • GenerationType.**IDENTITY**  기본키 생성을 DB에 위임 (AUTO_INCREMENT)
      • GenerationType.**SEQUENCE**  DB SEQUENCE를 이용해서 키 생성 + @SequenceGenerator
      • GenerationType.**TABLE**  키 생성 전용 테이블 사용 + @TableGenerator
      • GenerationType.**AUTO**(default)  JPA 구현체(Hibernate)가 생성 방식 결정
        • 오라클 → SEQUENCE , MySQL→ IDENTITY
  • **@Column**
    • 객체 필드를 DB Column에 매핑
    • 속성
      • name  : 필드와 매핑할 테이블 컬럼 이름 (default: 객체의 필드 이름)
      • nullable (DDL) : null 값 허용 여부 (default: true)
      • unique (DDL) : 유일값 제약조건
      • columnDefinition (DDL) : 컬럼 정보
      • Length (DDL) : 문자 길이 제약조건, String 타입에만 사용 (default: 255)
      • percision , scale (DDL) : BigDemical, BigInteger 타입에서 사용

  • @Transient
    • 필드 매핑X
    • 데이터베이스에 저장하지 않고 조회하지도 않는다.
    • 객체에 임시로 어떤 값을 보관하고 싶을 때 사용
  • 타입매핑 @Enumerated @Temporal @Lob
  • 연관관계 매핑 @ManyToOne @JoinColumn

JPA Repository 생성

JpaRepositry


Hibernate(JPA 구현체)를 이용하기 위해 Spring Data JPA가 제공하는 API 중 가장 많이 사용되는 인터페이스

/* Spring Data **JPA Repository** */

package SeSAC.spring.study.SeSACspringstudy.repository;
**import org.springframework.data.jpa.repository.JpaRepository;**
import SeSAC.spring.study.SeSACspringstudy.domain.Board;
**import java.util.Optional;**

																	// **extends JpaRepository<객체, PK타입>**
**public interface** SD_BoardRepository **extends JpaRepository<Board, Integer>** {
    
		Optional<Board> findByName(String name);

}
  • JpaRepository 상속 → SQL문 없이 CRUD 작업 가능
  • 제네릭 타입 <Entity, PK 타입> 지정 → Spring Data JPA가 자동으로 스프링의 빈(bean)으로 등록
    • [ 스프링이 내부적으로 인터페이스 타입에 맞는 객체를 생성해서 빈으로 등록 ]
/* 직접 만든 JPA Repository */

package SeSAC.spring.study.SeSACspringstudy.repository;
**import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;**
import SeSAC.spring.study.SeSACspringstudy.domain.Board;
**import javax.persistence.*;**
import java.util.*;

**@Repository
@RequiredArgsConstructor**
**public class** JPARepository **implements BoardRepository** {

    **private final EntityManager** em;

    @Override
    public Board save(Board board) {
        this.**em.persist**(board);
        return board;
    }

    @Override
    public Optional<Board> findById(int id) {
        return **Optional.empty();**
    }

    @Override
    public Optional<Board> findByName(String name) {
        return **Optional.empty();**
    }

    @Override
    public List<Board> findAll() {
        // Select * from board as b;
        return **em.createQuery**("select b from Board b", Board.class)
                .getResultList();   // List<Board>
    }
}

테스트를 통한 CRUD 기능 확인

Create

Repository 객체의 save() 메소드를 사용

@SpringBootTest
public class MemoRepositoryTest {
 
    @Autowired
    MemoRepository memoRepository;
 
    @Test
    public void InsertDummies() {
 
        IntStream.rangeClosed(1, 10).forEach(i -> {
            Memo memo = Memo.builder()
                    .memoText("Sample..." + i)
                    .build();
            //Create!
            memoRepository**.save**(memo);
        });
    }

Read

findById()

  • 해당하는 객체를 Optional 타입으로 반환
  • 한번 더 결과가 존재하는지 체크
@SpringBootTest
public class MemoRepositoryTest {
 
    @Autowired
    MemoRepository memoRepository;
 
    @Test
    public void SelectDummies() {
 
        Long id = 10L;
 
        **Optional**<Memo> result = memoRepository**.findById(**id);
 
        System.out.println("=============================");
 
        if(result.isPresent()) {
            Memo memo = result.get();
            System.out.println(memo);
        }
    }
}

Update

save()

내부적으로 해당 엔티티의 @Id값이 일치하는지를 확인해서 insert 혹은 update 작업을 처리

  • JPA는 엔티티 객체들을 메모리상에 보관하려고 하기 때문에
  • 특정한 엔티티 객체가 존재하는지 확인하는 select가 먼저 실행되고
  • 해당 @Id를 가진 엔티티 객체가 있다면 update, 그렇지 않다면 insert 실행
@SpringBootTest
public class MemoRepositoryTest {
 
    @Autowired
    MemoRepository memoRepository;
 
    @Test
    public void UpdateDummies() {
        Memo memo = Memo.builder()
                .id(10L)
                .memoText("Update Text")
                .build();
 
        memoRepository**.save**(memo);
    }

Delete

  • 수정 작업과 동일한 개념으로 삭제하려는 엔티티 객체가 있는지 먼저 확인하고, 삭제

Spring Data JPA

JPA (Java Persistence API)

ORM(Object-Relational Mapping) 기술 표준으로 사용되는 자바 인터페이스 모음

  • 장점: 유지보수 용이, DBMS 종속성X
  • 단점: 복잡하고 학습 어려움

  • JPA Hibernate (오픈소스)
  • JPA vs MyBatis (sequelize vs MySQL)

[Spring Boot] MySQL & JPA 연동 및 테스트

프로젝트에 의존성 추가

  • build.gradle에 추가 후 build
  • implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'mysql:mysql-connector-java'

application.properties 설정에 DB 정보 추가

server.address=localhost
server.port=8080 

# MySQL 설정
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# DB Source URL
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sesac?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8&serverTimezone=Asia/Seoul
spring.datasource.username=~~~
spring.datasource.password=~~~

# mysql 연동
spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

#true 설정시 JPA 쿼리문 확인 가능
spring.jpa.show-sql=true

# JPA의 구현체인 Hibernate가 동작하면서 발생한 SQL의 가독성을 높여준다.
spring.jpa.properties.hibernate.format_sql=true

# DDL(Create, Alter, Drop) 정의시 DB의 고유 기능을 사용할 수 있다.
**spring.jpa.hibernate.ddl-auto=**create

데이터베이스 스키마 자동 생성 기능

  • 클래스의 매핑 정보와 데이터베이스 방언을 사용하여 데이터베이스 스키마 생성
  • 어플리케이션 실행 시점에 데이터베이스 테이블 자동 생성
  • application.properties 에 속성 추가
  • spring.jpa.hibernate.ddl-auto 속성
    • create : 기존 테이블 삭제하고 새로 생성 [ DROP + CREATE ]
    • create-drop : create 속성 + 어플리케이션 종료할 때 생성한 DDL 제거 [ DROP + CREATE + DROP ]
    • update : DB 테이블과 엔티티(domain 패키지 파일) 매핑 정보를 비교하고 변경사항만 수정 [ ALTER + CREATE ]
    • none : 자동 생성 기능을 사용하지 않음

Error

JPA Hibernate 엔티티(Entity) 매핑

/* **Hibernate Entity** : domain 패키지 내 파일 */

@Getter 
@Builder // 객체 생성
@AllArgsConstructor
@NoArgsConstructor

@Table(name = "tbl_memo")
@Entity
public class Memo {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) //MySQL의 AUTO_INCREMENT를 사용
    private Long id;
 
    @Column(length = 200, nullable = false)
    private String memoText;
 
}

Entity 매핑 annotation

  • **@Entity** ❗
    • DB 테이블과의 매핑
    • @Entity가 붙은 클래스는 JPA가 관리
    • 속성
      • Name : PA에서 사용할 엔티티 이름을 지정한다. (보통 default값인 클래스 이름을 사용)
    • 주의사항
      • 기본 생성자 필수 (JPA가 엔티티 객체 생성 시 기본 생성자를 사용하기 때문)
      • final 클래스, enum, interface, inner class 에는 사용할 수 없다.
      • 저장할 필드에 final 사용 불가
  • **@Table**
    • 엔티티와 매핑할 테이블 지정 (클래스 명과 같은 경우 생략 가능)
    • 생략 시 매핑한 엔티티 이름을 테이블 이름으로 사용
    • 속성
      • Name  : 매핑할 테이블 이름 (default. 엔티티 이름 사용)
      • CataLog  : catalog 기능이 있는 DB에서 catalog 를 매핑 (default. DB 명)
      • Schema  : schema 기능이 있는 DB에서 schema를 매핑
      • uniqueConstraints : DDL 생성 시 유니크 제약조건을 만듦 스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용
  • **@Getter**
  • **@Id**
  • **@GeneratedValue**  PK 생성 전략
    • 직접 할당
      • em.persist() 호출 전 어플리케이션에서 직접 식별자 값 할당
    • 자동 생성
      • GenerationType.**IDENTITY**  기본키 생성을 DB에 위임 (AUTO_INCREMENT)
      • GenerationType.**SEQUENCE**  DB SEQUENCE를 이용해서 키 생성 + @SequenceGenerator
      • GenerationType.**TABLE**  키 생성 전용 테이블 사용 + @TableGenerator
      • GenerationType.**AUTO**(default)  JPA 구현체(Hibernate)가 생성 방식 결정
        • 오라클 → SEQUENCE , MySQL→ IDENTITY
  • **@Column**
    • 객체 필드를 DB Column에 매핑
    • 속성
      • name  : 필드와 매핑할 테이블 컬럼 이름 (default: 객체의 필드 이름)
      • nullable (DDL) : null 값 허용 여부 (default: true)
      • unique (DDL) : 유일값 제약조건
      • columnDefinition (DDL) : 컬럼 정보
      • Length (DDL) : 문자 길이 제약조건, String 타입에만 사용 (default: 255)
      • percision , scale (DDL) : BigDemical, BigInteger 타입에서 사용

  • @Transient
    • 필드 매핑X
    • 데이터베이스에 저장하지 않고 조회하지도 않는다.
    • 객체에 임시로 어떤 값을 보관하고 싶을 때 사용
  • 타입매핑 @Enumerated @Temporal @Lob
  • 연관관계 매핑 @ManyToOne @JoinColumn

JPA Repository 생성

JpaRepositry


Hibernate(JPA 구현체)를 이용하기 위해 Spring Data JPA가 제공하는 API 중 가장 많이 사용되는 인터페이스

/* Spring Data **JPA Repository** */

package SeSAC.spring.study.SeSACspringstudy.repository;
**import org.springframework.data.jpa.repository.JpaRepository;**
import SeSAC.spring.study.SeSACspringstudy.domain.Board;
**import java.util.Optional;**

																	// **extends JpaRepository<객체, PK타입>**
**public interface** SD_BoardRepository **extends JpaRepository<Board, Integer>** {
    
		Optional<Board> findByName(String name);

}
  • JpaRepository 상속 → SQL문 없이 CRUD 작업 가능
  • 제네릭 타입 <Entity, PK 타입> 지정 → Spring Data JPA가 자동으로 스프링의 빈(bean)으로 등록
    • [ 스프링이 내부적으로 인터페이스 타입에 맞는 객체를 생성해서 빈으로 등록 ]
/* 직접 만든 JPA Repository */

package SeSAC.spring.study.SeSACspringstudy.repository;
**import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;**
import SeSAC.spring.study.SeSACspringstudy.domain.Board;
**import javax.persistence.*;**
import java.util.*;

**@Repository
@RequiredArgsConstructor**
**public class** JPARepository **implements BoardRepository** {

    **private final EntityManager** em;

    @Override
    public Board save(Board board) {
        this.**em.persist**(board);
        return board;
    }

    @Override
    public Optional<Board> findById(int id) {
        return **Optional.empty();**
    }

    @Override
    public Optional<Board> findByName(String name) {
        return **Optional.empty();**
    }

    @Override
    public List<Board> findAll() {
        // Select * from board as b;
        return **em.createQuery**("select b from Board b", Board.class)
                .getResultList();   // List<Board>
    }
}

테스트를 통한 CRUD 기능 확인

Create

Repository 객체의 save() 메소드를 사용

@SpringBootTest
public class MemoRepositoryTest {
 
    @Autowired
    MemoRepository memoRepository;
 
    @Test
    public void InsertDummies() {
 
        IntStream.rangeClosed(1, 10).forEach(i -> {
            Memo memo = Memo.builder()
                    .memoText("Sample..." + i)
                    .build();
            //Create!
            memoRepository**.save**(memo);
        });
    }

Read

findById()

  • 해당하는 객체를 Optional 타입으로 반환
  • 한번 더 결과가 존재하는지 체크
@SpringBootTest
public class MemoRepositoryTest {
 
    @Autowired
    MemoRepository memoRepository;
 
    @Test
    public void SelectDummies() {
 
        Long id = 10L;
 
        **Optional**<Memo> result = memoRepository**.findById(**id);
 
        System.out.println("=============================");
 
        if(result.isPresent()) {
            Memo memo = result.get();
            System.out.println(memo);
        }
    }
}

Update

save()

내부적으로 해당 엔티티의 @Id값이 일치하는지를 확인해서 insert 혹은 update 작업을 처리

  • JPA는 엔티티 객체들을 메모리상에 보관하려고 하기 때문에
  • 특정한 엔티티 객체가 존재하는지 확인하는 select가 먼저 실행되고
  • 해당 @Id를 가진 엔티티 객체가 있다면 update, 그렇지 않다면 insert 실행
@SpringBootTest
public class MemoRepositoryTest {
 
    @Autowired
    MemoRepository memoRepository;
 
    @Test
    public void UpdateDummies() {
        Memo memo = Memo.builder()
                .id(10L)
                .memoText("Update Text")
                .build();
 
        memoRepository**.save**(memo);
    }

Delete

  • 수정 작업과 동일한 개념으로 삭제하려는 엔티티 객체가 있는지 먼저 확인하고, 삭제

'새싹🌱' 카테고리의 다른 글

TDD  (0) 2024.03.08
Redux  (0) 2022.11.25
[JAVA] RequestMapping Handler Method  (0) 2022.11.16
221109 JAVA 입문  (0) 2022.11.09
0907 Socket.io  (0) 2022.09.07