반응형
역시 기계는 솔직하다
삽질(이전글1, 이전글2)은 내가 해놓고 원인을 못찾고있었으니...
데이터를 먼저 올리고 Auto Increase가 안될 때 여러가지 경우가 있다.(경험치....)
- @GeneratedValue 전략이 잘못 되었을 때
GeneratedValue에서 기준이 잘못되어 ID값이 잘못 부여되는 경우가 많다고 한다. (관련 글) - properties 혹은 yml파일에서의 설정
- Spring에서는 Script-base 방식과 Hibernate의 생성 방식과 같이 다양한 데이터 초기화 기술을 함께 쓰는 것을 권장하지 않음(참고 글)
- init.schema 후 init.data / 세트로 둘이 같이 있어야 한다.
# application.properties spring.jpa.database=h2 spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=create spring.jpa.generate-ddl=true spring.jpa.show-sql=true spring.sql.init.schema-locations=classpath*:/static/db/h2.sql spring.sql.init.data-locations=classpath*:/static/db/insert.sql # application.yml spring: jpa: database: h2 database-platform: org.hibernate.dialect.H2Dialect hibernate ddl-auto: create generate-ddl: true show-sql: true sql: init: schema-locations: classpath*:/static/db/h2.sql data-locations: classpath*:/static/db/insert.sql
- 데이터를 먼저 추가할 때의 DDL, DML 작성
테이블 관계를 생각해서 FK가 있다면 바라보는(참조되는) 테이블 및 데이터를 먼저 정의
<!-- DDL --> CREATE TABLE member( member_id bigint primary key NOT NULL auto_increment, nick_name varchar(10) NOT NULL, email varchar(50) NOT NULL, password varchar(20) NOT NULL, acc_time varchar(10), member_status varchar(10) NOT NULL ); CREATE TABLE board( board_seq bigint primary key NOT NULL auto_increment, title varchar(50) NOT NULL, content varchar(200) NOT NULL, board_ctgr varchar(10) NOT NULL, board_status varchar(10) NOT NULL, member_id bigint NOT NULL ); <!-- DML : @ID를 입력하지 않아도 괜찮다. --> -- MEMBER TABLE INSERT INTO member ( nick_name, email, password, member_status ) VALUES ( 'JOY', 'test@test.com', 'test1234', 'Active' ); -- BOARD TABLE INSERT INTO board ( title, content, board_ctgr, board_status, member_id ) VALUES( 'test1', 'test_text1', 'noti', 'Active', 1 );
한줄 요약하면
Entity의 @GeneratedValue 전략 확인, properties 혹은 yml에서 jpa와 sql 초기화 부분확인, DDL, DML 추가 순서 확인
+ ) auto_increase는 해결 되었으나 기존에 밀어 넣으려던 데이터가 삽입되지 않았다.
LogLevel을 한단계 상위에 Trace를 걸어주었다.
logging.level.root=DEBUG
logging.level.org.springframework=TRACE
logging.level.org.springframework.jdbc=DEBUG
logging.level.org.hibernate=TRACE
logging.level.org.hibernate.SQL=DEBUG
로그를 확인중에 깨달은 사실
[ datasource.init ] : Create - [ datasource.init ] : Insert - [ hibernate ] : Drop - [ hibernate ] : Create
이렇게만 진행된다.
그러니 데이터가 없을 수 밖에....
++ ) 그리고 db를 Embeded로 했는지 In-Memory로 했는지도 실행의 분기점이 되었던것 같다.
내가 해본 케이스들을 정리해 보았다.
Embeded / In-Memory | ddl-auto | init | insert_seq필요 | data유무 | auto_increase |
Embeded | none | defer-datasource-initialization=true | dont' need | 없음 | SUCCESS |
init.mode=always | need | hibernate 중복 | - | ||
create | update | defer-datasource-initialization=true | dont' need | 없음 | SUCCESS | |
init.mode=always | need | hibernate 중복 | - | ||
create-drop | defer-datasource-initialization=true | dont' need | 없음 | SUCCESS | |
init.mode=always | need | hibernate 중복 | - | ||
In-Memory | none | defer-datasource-initialization=true | need | 없음 | Fail |
init.mode=always | dont' need | 있음 | SUCCESS | ||
create |
defer-datasource-initialization=true | need | 있음 | Fail | |
init.mode=always | dont' need | 없음 | SUCCESS | ||
update | defer-datasource-initialization=true | need | 있음 | Fail | |
init.mode=always | dont' need | 있음 | SUCCESS | ||
create-drop | defer-datasource-initialization=true | need | 있음 | Fail | |
init.mode=always | dont' need | 없음 | SUCCESS |
+++ ) 초기화를 같이 하면 안된다고 생각하고 있었다.
하지만 찾아보다보니 어디는 같이 사용하면 안된다고 하고.. 어디는 같이 사용해도 괜찮다고 하고...
결과적으로는 같이 사용해도 괜찮았다...
logging.level.root=DEBUG
logging.level.org.springframework=TRACE
logging.level.org.springframework.jdbc=DEBUG
logging.level.org.hibernate=TRACE
logging.level.org.hibernate.SQL=DEBUG
spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.datasource.url=jdbc:h2:mem:testdb
#spring.datasource.url=jdbc:h2:~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database=h2
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.defer-datasource-initialization=true
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath*:/static/db/h2.sql
spring.sql.init.data-locations=classpath*:/static/db/insert.sql
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
Spring Boot에서는 `spring.jpa.hibernate.ddl-auto` 설정과 `spring.sql.init` 설정을 통해 데이터베이스 초기화 순서를 제어할 수 있습니다.
`spring.jpa.hibernate.ddl-auto` 속성이 `create` 또는 `create-drop`으로 설정되어 있으면 Hibernate가 데이터베이스 스키마를 생성합니다.
`spring.sql.init.mode` 속성은 SQL 스크립트를 통한 초기화를 제어합니다.
`spring.jpa.hibernate.ddl-auto`가 `create`로 설정되어 있고, `spring.sql.init.mode`가 `always`로 설정되어 있다면, 일반적으로 Hibernate가 먼저 실행되어 스키마를 생성하고, 그 다음에 `spring.sql.init` 설정에 따라 SQL 스크립트가 실행됩니다.
문제는 `spring.jpa.defer-datasource-initialization` 설정 때문에 발생할 수 있습니다.
이 설정이 `true`일 경우, 데이터 소스 초기화가 ApplicationContext가 완전히 로드된 후까지 지연됩니다.
이는 `spring.sql.init` 스크립트가 Hibernate DDL 실행 후에 실행되도록 하는데 도움이 될 수 있지만, 주석 처리되어 있어 현재 활성화되어 있지 않습니다.
현재 설정에서 Hibernate가 `spring.sql.init`보다 먼저 실행되어야 하는 것이 목표라면, 다음과 같이 확인해야 합니다:
1. `spring.jpa.hibernate.ddl-auto`가 `create` 또는 `create-drop`으로 설정되어 있는지 확인: 이 설정이 데이터베이스 스키마 생성을 제어합니다.
2. `spring.jpa.defer-datasource-initialization`를 `true`로 설정: 이는 `spring.sql.init` 스크립트 실행을 지연시켜 Hibernate가 스키마를 먼저 생성할 수 있도록 합니다.
3. `spring.sql.init.mode` 설정 확인: 이 설정은 SQL 스크립트가 언제 실행될지를 제어합니다. `always`로 설정되어 있다면, ApplicationContext 로딩이 완료된 후에 SQL 스크립트가 실행됩니다.
위의 설정을 통해 Hibernate가 먼저 데이터베이스 스키마를 생성하고, 그 다음에 `spring.sql.init`에 의해 SQL 스크립트가 실행되도록 할 수 있습니다.
설정이 이미 이와 같이 구성되어 있다면, Hibernate가 먼저 스키마를 생성하고 이후에 SQL 초기화 스크립트가 실행되어야 합니다.
반응형
'Backend > Spring | SpringBoot' 카테고리의 다른 글
[Spring] redirect경로 (0) | 2024.03.13 |
---|---|
[Spring Security] CSRF 토큰 (0) | 2024.03.13 |
[JDBC] java.sql.SQLException: No suitable driver found for jdbc:mariadb (0) | 2024.03.07 |
[REST API] @Controller / @RestController (0) | 2024.03.05 |
[JPA] insert...ing (0) | 2024.03.04 |