H2 DB in-memory를 사용하고 있다.
따라서 Data가 유지되지 않고, test가 끝나는 시점에 data가 사라지게 된다.
JPA Repository에서 제공하고 있는 메서드들의 많은 부분들이 조회와 관련한 것
→ 따라서 기본적인 Data를 사전에 만들어두고 조회를 해야 함
가장 쉽게 사용할 수 있는 것이 data.sql 파일이다.
data.sql 파일을 resources 하위에 두면 JPA가 로딩할 때, 자동으로 해당 쿼리를 한번 실행해준다.
test할 때 사용하기 위해서는 test 하위에 resources를 두고 data.sql 파일을 만들어주면 된다.
main폴더에는 원래 resources 폴더가 있는 반면, test에는 없다.
- resources 하위에 data.sql까지 만들면 된다.
- 이렇게 test 하위에 resources를 넣으면 test가 동작할 때만 쿼리를 실행시켜준다.
id를 순차적으로 증가시키기 위해 call next value for hibernate_sequence; 작성
이렇게 5개 정도의 예시를 만들어 놓고 test 실행해보기 (UserRepositoryTest)
오류 발생
❗ Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Sequence "HIBERNATE_SEQUENCE" not found; SQL statement:
원인
H2 db 사용, entity class 에 테이블명을 명시해주지 않았기 때문에
데이터 등록 처리 중 해당 에러 발생 (테이블 시퀀스 값이 없다는 상황)
@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 해결법
@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 설정한 후
위 처럼 쿼리가 정렬되어 출력된 이유는 properties 설정 때문이다.
jpa:
defer-datasource-initialization: true
show-sql: true # default : show-sql: false -> true로 바꾸면서 sql문을 보여준다.
properties:
hibernate:
format_sql: true
findAll() 에 Sort parameter 추가
- 이름 내림차순으로 조회
- 실제 쿼리를 보면, order by users0_.name desc 쿼리가 추가되었다.
Lists.newArrayList(1L, 3L, 5L)
// 위의 코드는 다음과 같다.
List<Long> ids = new ArrayList<>();
ids.add(1L);
ids.add(3L);
ids.add(5L);
save() 사용
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());
잘 통과된다.
따라서, 순차적으로 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을 통해서 Session을 유지시켜준다.
getOne은 기본적으로 Entity에서 lazy한 로딩을 지원하고 있다. (lazy fetch 지원)
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 |