P4-1] Ch 02. SpringData JPA 기초

uuuu.jini·2022년 1월 24일
0
post-thumbnail

목차

  1. Repository interface 계층
  2. Repository interface 메소드 실습
  3. SimpleJpaRepository 코드 보기

github 링크

1. Repository interface 계층

자바 객체 - entity로 사용하며(@Entity 어노테이션 작성 필), 해당 객체를 저장하고 조회하기 등의 기능을 수행하기 위한 클래스로 repository를 사용하며 해당 클래스는 JpaRepository 를 상속받음으로써 spring이 지원하는 많은 jpa 기능을 제공해준다. [JpaRepository class 상속시 제너릭타입으로 entity 타입과 primary key 타입을 받는다] 해당 기능 중 저장과 조회 기능을 테스트 해보기 위하여 생성한 repository 객체를 @AutoWired를 통해 주입받고 클래스의 save 메소드와 findAll메소드를 사용한 예제를 밑에 작성해 보았다.

@SpringBootTest
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void crud(){ 
        userRepository.save(new User()); 
        System.out.println(">>> " + userRepository.findAll());
    
}

실제로 일바적으로 성능이슈로 인하여 findAll메서드는 사용하지 않는다. 해당 기능 관련된 다양한 메서드가 존재하며 차차 익혀나갈 것이다.


2. Repository Interface 메소드 실습

db를 미리 구성해두고 사용하기 위하며 resources하위에 data.sql이라는 파일을 생성하여 작성해줄 경우 서버를 실행시키기 전에 해당 쿼리를 미리 실행하여 준다. test하기 위하여 test하위에 해당 파일을 생성해 주었다. 즉 test가 동작할 때만 해당 쿼리가 동작하게 된다. main에 넣어주게 되면 spring boot run 시마다 해당 쿼리가 동작한다.

쿼리 내부에 데이터를 생성하여 삽입하여 주었다. 해당 쿼리는 아래와 같다. 쿼리를 여러번 반복하여 여러개의 데이터를 생성하였다.

call next value for hibernate_sequence;
insert into user('id', 'name', 'email', 'create_at', 'update_at') values (1, 'yoojin', 'yooijn@naver.com', now(), now());

첫번째 에러 : User not found - spring boot 2.5버전 부터는 data.sql이 Hibernate가 초기화되기 전에 실행된다.Hibernate 초기화를 통해 생성된 스키마에 데이터를 입력하기 위해 data.sql을 실행하려면 application.yml파일에 spring.jpa.defer-datasource-initialization = true 를 작성한다.

두번째 에러 : expected "identifier" 에러 해당 에러는 예약어가 해당 쿼리 내에 있을 경우 발생하는 에러이다. 위의 내가 작성한 코드를 보면 insert into user 뒤의 필드 병에 ''로 필드를 묶엇지만 해당 필드 명들은 `(back tick) 을 사용해야 한다. 즉 위의 코드는 아래의 코드로 변경되어야 한다.

call next value for hibernate_sequence;
insert into user(`id`,`name`,`email`,`create_at`,`update_at`) values (1, 'yoojin', 'yooijn@naver.com', now(), now());

모든 에러 해결 참조 문서 : 참조

실제 실행되는 쿼리를 로그로 출력해주기 위해서는 application.yml파일 spring.jpa.show-sql: true로 변경한다.
보기 좋게 로그를 출력시켜주기 위해서는 spring.jpa.properties.hibernate.format_sql:true로 설정한다.

ORM은 자바 객체와 db 레코드간의 연결관계를 맺어주는 것이다. 최종적으로 동작하는 것은 sql query가 된다. 어떤 메소드 호출시 어떤 쿼리가 생성되는지 로그를 살펴봄으로써 jpa동작 이해에 도움이 된다.

findAll() 메서드

모든 요소들의 리스트를 반환한다. 해당 반환된 list의 요소 하나를 한줄 씩 출력을 위해서는

	userRepository.findAll().stream().forEach(System.out::println);

를 사용한다. [스트림,람다 학습]

findAll(Sort) 메서드

sort기준을 지정하여 모든 요소들의 list를 반환한다.

        List<User> users = userRepository.findAll(Sort.by(Sort.Direction.DESC,"name")); 
        users.forEach(System.out::println);

name을 기준으로 내림차순으로 정렬이 된다.

findAllById 메서드

id리스트를 인자로 받아서 해당 id에 해당하는 요소들의 리스트를 반환한다. test용도로 인자내부에서 리스트를 생성하는 List.newArray(인자들)을 사용할 수 있다.( 단순히 리스트를 먼저 생성하고 대입하여도 된다.)

	List<User> users1 = userRepository.findAllById(Lists.newArrayList(1L, 2L, 3L));
	Lists.newArrayList(요소)
        users1.forEach(System.out::println);

saveAll 메서드

저장할 entity의 리스트를 인자로 받아 저장한다.

	User user1 = new User("jack", "jack@naver.com");
        User user2 = new User("steve", "steve@naver.com");

        userRepository.saveAll(Lists.newArrayList(user1, user2));

getOne 메서드 & findById 메서드

getOne메서드는 entity를 받아오며 lazy 연결로 @Transactional 어노테이션이 필요하다. findById메서드는 optional 로 맵핑된 entity 를 받아온다. (둘다 id에 해당하는 entity 받아옴)

   	User user = userRepository.getOne(1L);
        System.out.println(user);
        
        User user = userRepository.findById(1L).orElse(null); 
        System.out.println(user);

flush 메서드 & saveAndFlush 메서드

저장 & flush 하는 메서드이다.

count 메서드

long형식으로 전체요소의 수를 반환한다.

existById 메소드

해당 id 를 가진 entity가 존재하는지 여부를 boolean 형으로 반환한다.

delete 메서드 & deleteById 메서드

해당 entity 를 제거하거나 해당 id를 가진 entity 를 제거한다.

deleteAll 메서드

전체 요소를 제거하거나, 해당 id리스트의 entitiy를 제거한다.

userRepository.deleteAll(userRepository.findAllbyId(Lists.newArrayList(1L,2L);

delete 메서드는 성능 이슈로 인해 실제로 잘 사용하지 않으며, delete전에 항상 select로 해당 엔티티의 존재여부를 먼저 확인한다.

deleteInBatch 메서드 & deleteAllInBatch 메서드

delete전에 존재여부를 확인하는 select문 없이 바로 delete를 수행한다.

Paging

전체 요소를 원하는 size수로 나눈 페이지 중 원하는 페이지를 반환해주는 기능을 제공한다.

	Page<User> users = userRepository.findAll(PageRequest.of(1,3));

findAll 메서드의 pageRequest객체의 of메서드의 인자로 원하는 pagesize를 인자로 넘겨주면 전체 요소들을 size로 나눈 후 page를 가져온다.

반환된 page 객체는 여러 속성을 가지고 있다.

Query by Example

entity 를 example로 만들고 matcher를 추가 선언하여 원하는 쿼리를 만드는 방법으로 쿼리로 해당 요소들을 반환한다.

해당 방법은 많이 사용하는 방법이 아니므로 간단히 알고 넘어간다.


3. SimpleJpaRepository 분석

@Transactional 어노테이션 ?

Update 기능

save메서드 실행시 id가 이미 존재하는 id일경우 update문이 실행된다.

   @Test
   void update(){
       userRepository.save(new User("david", "david@google.com"));

       User user = userRepository.findById(1L).orElseThrow(RuntimeException::new);
       user.setEmail("yoojin-update@naver.com");

       userRepository.save(user); 
   }
profile
멋쟁이 토마토

0개의 댓글