관리 메뉴

bright jazz music

JpaRepository + 페이징, 쿼리메소드 본문

Framework/Spring

JpaRepository + 페이징, 쿼리메소드

bright jazz music 2022. 6. 23. 08:49
package org.zerok.ex2.repository;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.test.annotation.Commit;
import org.zerok.ex2.entity.Memo;

import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;

@SpringBootTest
public class MemoRepositoryTests {

    @Autowired
    MemoRepository memoRepository;

    @Test
    public void testClass(){
        System.out.println(memoRepository.getClass().getName());

        /*
         * testClass()메서드는 MemoRepository 인터페이스 타입의 실제 객체가 어떤 것인지 확인한다.
         * 스프링이 내부적으로 해당 클래스를 자동생성(AOP)하는데, 이 때 선언한 적 없는 클래스의 이름이
         * com.sun.proxy.$Proxy110 와 같이 콘솔에 출력된다.(동적 프록시 방식으로 생성됨)
         *
         *
         * */
    }


    @Test //등록작업 테스트
    public void testInsertDummies(){
        IntStream.rangeClosed(1,100).forEach(i -> {
            Memo memo = Memo.builder().memoText("Sample..." + i).build();
            memoRepository.save(memo);
        });

        //한 번에 여러 개의 객체를 저장하도록 작성. 100개의 Memo 객체를 생성하고 MemoRepository를 이용해서 insert.
        // 두 번 실행하면 테이블에 행이 200번까지 만들어진다.
    }

    @Test   //조회작업 테스트: findById()사용
    public void testSelect(){
        //DB에 존재하는 mno
        Long mno = 100L;

        Optional<Memo> result = memoRepository.findById(mno);
        //100번이 존재하지 않더라도 오류를 반환하지 않음. 물론 객체도 반환되지 않음.

        System.out.println("==============================");

        if(result.isPresent()) {
            Memo memo = result.get();
            System.out.println(memo);
        }
        /*
        * 조회 작업의 테스트는 findById()나 getOne()을 이용해서 엔티티 객체를 조회할 수 있다.
        * findById()와 getOne()은 동작하는 방식이 조금 다르다.
        * DB를 먼저 이용하는지, 필요한 순간까지 미루는지에 대한 차이이다.
        *
        * findById()는 DB를 먼저 이용해서 값을 가져온다.
        * findById()를 실행한 순간에 이미 sql은 처리되었고
        *
        * findById()의 경우 java.util 패키지의 Optional 타입으로 반환되기 때문에
        * 한 번 더 결과가 존재하는지 체크하는 형태로 작성하게 된다.
        * "==============================" 부분은 SQL 처리 이후에 실행된다.
        * */
    }

    @Transactional //트랜잭션 처리를 위해 사용하는 어노테이션. 없으면 오류 반환: no session
    @Test   //조회작업 테스트: getOne()사용
    public void testSelect2(){
        Long mno = 101L;

        Memo memo = memoRepository.getOne(mno);
        //리턴 값은 해당 객체이지만 필요한 순간까지 sql을 실행하지 않는다.
        //해당 값이 테이블에 존재하지 않으면 오류 반환: Unable to find org.zerok.ex2.entity.Memo with id 100
        //getOne()은 depricated됨. getReferenceById()로 대체. testSelect3()에서 사용

        System.out.println("==============================");

        System.out.println(memo);//실제 객체를 사용하는 순간에 SQL이 동작한다.

    }

    @Transactional //트랜잭션 처리를 위해 사용하는 어노테이션. 없으면 오류 반환: no session
    @Test   //조회작업 테스트: getOne()사용
    public void testSelect3(){
        Long mno = 101L;

        Memo memo = memoRepository.getReferenceById(mno); //getOne() 대신에 사용
        //리턴 값은 해당 객체이지만 필요한 순간까지 sql을 실행하지 않는다.
        //해당 값이 테이블에 존재하지 않으면 오류 반환 : Unable to find org.zerok.ex2.entity.Memo with id 100
        //getOne()은 depricated됨. getReferenceById()로 대체. testSelect3()에서 사용

        System.out.println("==============================");

        System.out.println(memo);//실제 객체를 사용하는 순간에 SQL이 동작한다.

    }

    @Test
    public void testUpdate(){ //수정작업
        Memo memo = Memo.builder().mno(100L).memoText("Update Text").build();

        System.out.println(memoRepository.save(memo));

        /*
        * 수정작업은 등록작업과 동일하게 save()를 이용해서 처리한다.
        * 내부적으로 해당 엔티티의 @Id 값이 일치하는지 확인해서 insert 혹은 update 작업을 처리한다.
        *
        * 여기서는 100번의 Memo객체를 만들고, save()를 호출한다.
        * 호출결과를 보면 내부적으로 select 쿼리로 해당 번호의 Memo 객체를 확인하고
        * 이를 update하는 것을 볼 수 있다.
        *
        * JPA는 엔티티 객체들을 메모리 상에 보관하려고 하기 때문에 특정한 엔티티 객체가 존재하는지
        * 확인하는 select가 먼저 실행되고 해당 @Id를 가진 엔티티 객체가 있다면 update를,
        * 그렇지 않다면 insert를 실행한다.
        * */
    }

    @Test
    public void testDelete(){
        Long mno = 100L;
        memoRepository.deleteById(mno);

        /*
        * 삭제 작업도 위와 동일한 개념이 적용된다. 삭제하려는 번호(mno)의 엔티티 객체가 있는지
        * 먼저 확인(select)하고 이를 삭제 시도한다.
        * deleteById()의 리턴 타입은 void이고 만일 해당 데이터가 존재하지 않으면
        * org.springframework.dao.EmptyResultAccessException 예외를 발생시킴.
        * */
    }

    @Test
    public void testPageDefault(){
        Pageable pageable = PageRequest.of(0, 10);
        Page<Memo> result = memoRepository.findAll(pageable);
        System.out.println(result);

        System.out.println("--------------------------------------");
        System.out.println("Total pages: " + result.getTotalPages());       // 총 몇 페이지
        System.out.println("Total Count: " + result.getTotalElements());    // 총 개수
        System.out.println("Total Number: " + result.getNumber());          // 현재 페이지 번호 0부터 시작
        System.out.println("Page Size: " + result.getSize());               // 페이지당 데이터 개수
        System.out.println("has next page?: " + result.hasNext());          // 다음 페이지 존재 여부
        System.out.println("first page? : " + result.isFirst());            // 시작페이지(0) 여부

        System.out.println("--------------------------------------");
        for(Memo memo : result.getContent()) {
            System.out.println(memo);
        }
    }

    @Test
    public void testSort(){
        Sort sort1 = Sort.by("mno").descending();
        Sort sort2 = Sort.by("memoText").ascending();
        Sort sortAll = sort1.and(sort2); //and를 이용한 연결. memo는 desc로, memoText는 asc로 정렬

        Pageable pageable = PageRequest.of(0, 10, sortAll);
        Page<Memo> result = memoRepository.findAll(pageable);

        result.get().forEach(memo -> {
            System.out.println(memo);
        });
    }

    @Test
    public void testQueryMethod(){
        List<Memo> list = memoRepository.findByMnoBetweenOrderByMnoDesc(70L, 80L);

        for (Memo memo : list){
            System.out.println(memo);
        }
    }
}

 

 

    @Test
    public void testPageDefault()

 

 

 @Test
    public void testSort()

 

 

@Test
    public void testQueryMethod()

 

package org.zerok.ex2.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import org.zerok.ex2.entity.Memo;

import java.util.List;

public interface MemoRepository extends JpaRepository<Memo, Long> {
    //JpaRepository를 사용할 때는 엔티티 타입 정보(여기서는 Memo클래스)와 @Id 타입을 지정한다.
    //SpringDataJpa는 인터페이스 선언만으로도 자동으로 bean으로 등록한다.
    //(내부적으로는 인터페이스 타입에 맞는 객체를 생성해서 빈으로 등록한다.)
    //선언이 끝났으면 test폴더-repository패키지생성-MemoRepositoryTests클래스를 작성해서 진행



    List<Memo> findByMnoBetweenOrderByMnoDesc(Long from, Long to);
    //쿼리메소드와 @Query를 사용하기 위해 선언. 이 메소드의 이름 자체가 질의문이 된다.

}

 

 

 

 @Commit
    @Transactional
    @Test
    public void testDeleteQueryMethod(){
        memoRepository.deleteMemoByMnoLessThan(10L); //10번 전까지의 데이터를 삭제

 

package org.zerok.ex2.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import org.zerok.ex2.entity.Memo;

import java.util.List;

public interface MemoRepository extends JpaRepository<Memo, Long> {
    //JpaRepository를 사용할 때는 엔티티 타입 정보(여기서는 Memo클래스)와 @Id 타입을 지정한다.
    //SpringDataJpa는 인터페이스 선언만으로도 자동으로 bean으로 등록한다.
    //(내부적으로는 인터페이스 타입에 맞는 객체를 생성해서 빈으로 등록한다.)
    //선언이 끝났으면 test폴더-repository패키지생성-MemoRepositoryTests클래스를 작성해서 진행



    void deleteMemoByMnoLessThan(Long num);
    //쿼리메소드와 @Query를 사용하기 위해 선언. 이 메소드의 이름 자체가 질의문이 된다.

}

 

mno가 20 미만인 행을 전부 삭제함. 이 때 한 번에 삭제하는 것이 아니라 하나씩 개별 삭제함. 비효율성 존재

 

Comments