본문 바로가기
💻 개발/Spring

Repository Interface 메소드 실습 (1)

by 컴쏘 2023. 7. 20.

H2 DB in-memory를 사용하고 있다.

따라서 Data가 유지되지 않고, test가 끝나는 시점에 data가 사라지게 된다.

JPA Repository에서 제공하고 있는 메서드들의 많은 부분들이 조회와 관련한 것

→ 따라서 기본적인 Data를 사전에 만들어두고 조회를 해야 함

 

가장 쉽게 사용할 수 있는 것이 data.sql 파일이다.

data.sql 파일을 resources 하위에 두면 JPA가 로딩할 때, 자동으로 해당 쿼리를 한번 실행해준다.

test할 때 사용하기 위해서는 test 하위에 resources를 두고 data.sql 파일을 만들어주면 된다.

main과 test 비교

main폴더에는 원래 resources 폴더가 있는 반면, test에는 없다.

[test 폴더 우클릭] - [New] - [Directory]
여기서 resources 클릭
test에 data.sql 생성

  • resources 하위에 data.sql까지 만들면 된다.
  • 이렇게 test 하위에 resources를 넣으면 test가 동작할 때만 쿼리를 실행시켜준다.

sql 쿼리문 작성

id를 순차적으로 증가시키기 위해 call next value for hibernate_sequence; 작성

5개 정도의 예시 만들기

이렇게 5개 정도의 예시를 만들어 놓고 test 실행해보기 (UserRepositoryTest)

 

오류 발생

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Sequence "HIBERNATE_SEQUENCE" not found; SQL statement:

오류 발생

원인

H2 db 사용, entity class 에 테이블명을 명시해주지 않았기 때문에

데이터 등록 처리 중 해당 에러 발생 (테이블 시퀀스 값이 없다는 상황)

해결 방안 1

@GeneratedValue(strategy = GenerationType.IDENTITY) 로 변경

+) @GeneratedValue는 default가 @GeneratedValue(strategy = GenerationType.AUTO) 이다.

 

다른 근본적인 해결방법

Spring Boot 2.5 Hibernate data.sql 에러

⚠️ Spring Boot 2.5 버전부터는 data.sql 이 Hibernate 가 초기화되기 전에 실행되어
Hibernate 초기화를 통해 생성된 스키마에 데이터를 입력하기 위해 data.sql 을 실행하려면
1) application.properties(yml) 에 spring.jpa.defer-datasource-initialization = true 를 추가
2) schema.sql을 추가 (권장하지 않음)
해야 한다.

현재 내 버전 = 2.7.x

근원적인 문제

spring.jpa.defer-datasource-initialization = true 추가

[Spring JPA] data.sql 동작방식 변경, hibernate_sequence not found 해결법

spring.jpa.defer-datasource-initialization = true 추가
해결 방안 2

@GeneratedValue(strategy = GenerationType.SEQUENCE) 로 변경

해결
다른 방식으로 출력

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

// 위의 코드는 다음 코드와 거의 비슷하다. 

for (User user : userRepository.findAll()) {
	System.out.println(user);
}

 

application.yml

jpa:
	defer-datasource-initialization: true
		show-sql: true # default : show-sql: false -> true로 바꾸면서 sql문을 보여준다. 
    ...

 

show-sql: true 설정한 후

show-sql: true 설정의 출력 값

위 처럼 쿼리가 정렬되어 출력된 이유는 properties 설정 때문이다.

jpa:
	defer-datasource-initialization: true
		show-sql: true # default : show-sql: false -> true로 바꾸면서 sql문을 보여준다. 
		properties:
	    hibernate:
        format_sql: true

전체 데이터 5개가 users table에 있는 것을 확인 가능

 

findAll() 에 Sort parameter 추가

이름 역순(내림차순)으로 출력

  • 이름 내림차순으로 조회
  • 실제 쿼리를 보면, order by users0_.name desc 쿼리가 추가되었다.

특정 id 값만 가져오기

Lists.newArrayList(1L, 3L, 5L)

// 위의 코드는 다음과 같다.
List<Long> ids = new ArrayList<>();
ids.add(1L);
ids.add(3L);
ids.add(5L);

 

save() 사용

save()

 

saveAll() 사용

saveAll()

 

data.sql에서 call next value for hibernate_sequence;를 주석 처리 해보자.

오류

오류가 뜬다.

이유 : 새로운 data jack이 id 1번을 가지고 들어가려는데 이미 1번을 가진 data가 있음

만약 data.sql에서 id = 1 을 가진 data를 다른 id로 바꾼다면 잘 통과된다.

 

이렇게 바꾸면?

//call next value for hibernate_sequence;
insert into users (`id`, `name`, `email`, `created_at`, `updated_at`) values (6, 'sohyun', 'sohyun@test.com', now(), now());

//call next value for hibernate_sequence;
insert into users (`id`, `name`, `email`, `created_at`, `updated_at`) values (2, 'user1', 'user1@test.com', now(), now());

//call next value for hibernate_sequence;
insert into users (`id`, `name`, `email`, `created_at`, `updated_at`) values (3, 'user2', 'user2@test.com', now(), now());

//call next value for hibernate_sequence;
insert into users (`id`, `name`, `email`, `created_at`, `updated_at`) values (4, 'user3', 'user3@test.com', now(), now());

//call next value for hibernate_sequence;
insert into users (`id`, `name`, `email`, `created_at`, `updated_at`) values (5, 'sohyun', 'sohyun@testtest.com', now(), now());

id 변경 결과

잘 통과된다.

따라서, 순차적으로 data의 id 값을 증가시키면서 insert를 하기 위해서는 call next value for hibernate_sequence; 이 코드가 필요하다.

 

오류 발생

오류 발생

could not initialize proxy [com.sohyun.jpa.bookmanager.domain.Users#1] - no Session

Session이 존재하지 않기 때문에 Proxy 초기화 불가

 

@Transactional을 통한 문제 해결

@Transactional을 통해서 Session을 유지시켜준다.

 

getOne은 기본적으로 Entity에서 lazy한 로딩을 지원하고 있다. (lazy fetch 지원)

 

findById 사용

findById 사용

Optional도 toString() 이 있기 때문에 별도의 처리가 필요하다.

별도의 처리해주기

orElse를 통해 id가 1인 객체가 없다면 null 반환하게 처리

실행시켜본다면 query에 where로 잘 처리되어있고, id가 1인 객체를 출력했다.


2023 KAKAO Tech Campus_BackEnd 선택 과정
Spring JPA와 Security 강의 정리 내용입니다.

'💻 개발 > Spring' 카테고리의 다른 글

Gradle 프로젝트 구축하기  (0) 2023.12.04
Framework와 Project  (0) 2023.11.29
Repository Interface 계층 살펴보기  (0) 2023.07.20
H2 DB 및 로그 설정  (0) 2023.07.18
Lombok 알아보기  (0) 2023.07.17