[Spring] GenerationTarget encountered exception accepting command : Error executing DDL "..." 에러 해결 방법

NCOOKIE·2023년 7월 27일
1

증상

프로젝트에서 JPA를 통해 새로운 Entity를 추가한 후 실행 시 다음과 같은 에러가 발생했었다.

2023-07-27 10:40:51,576  WARN 24760 --- [  restartedMain] o.h.t.s.i.ExceptionHandlerLoggedImpl     : GenerationTarget encountered exception accepting command : Error executing DDL "
    alter table broadcaster 
       drop 
       foreign key FKrysak2cuh7ie510kftb8n0ppr" via JDBC Statement

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "
    alter table broadcaster 
       drop 
       foreign key FKrysak2cuh7ie510kftb8n0ppr" via JDBC Statement
	at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlString(SchemaDropperImpl.java:419) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlStrings(SchemaDropperImpl.java:403) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.tool.schema.internal.SchemaDropperImpl.applyConstraintDropping(SchemaDropperImpl.java:373) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:256) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:178) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:149) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:117) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:242) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$5(SchemaManagementToolCoordinator.java:143) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at java.base/java.util.HashMap.forEach(HashMap.java:1421) ~[na:na]
	at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:140) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:336) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:415) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1423) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
	at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66) ~[spring-orm-6.0.8.jar:6.0.8]
	at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376) ~[spring-orm-6.0.8.jar:6.0.8]
	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-6.0.8.jar:6.0.8]

...

원인

처음에 위의 에러가 여러 개 떠서 모두 하나의 문제인줄 알았는데, 자세히 보니 단순한 WARN인 것도 있었고 ERROR인 것도 있었다. 각자 다른 문제가 원인이었다.

예약어

대부분의 경우 데이터베이스에서 사용하는 이름을 SQL 예약어를 사용한 것이 문제였다. 각자 사용하는 데이터베이스의 예약어를 확인하여 겹치는 것이 있는지 확인해보자. 이 문제를 해결하는 방법은 여러 가지가 있다.

해결법 1

https://dev.mysql.com/doc/refman/8.0/en/keywords.html

가장 간단한 방법이다. 예약어와 겹치는 이름을 다른 것으로 수정해준다.

해결법 2

@Column 어노테이션을 사용하여 칼럼 이름을 직접 지정해준다.

@Column(name = "\"rate\"")
private int rate;

해결법 3

globally_quoted_identifiers 옵션을 true로 설정해준다. 이러면 SQL문이 실행될 때 백틱(`)로 테이블과 컬럼을 자동으로 감싸준다.

spring:
  jpa:
    properties:
      hibernate:
        globally_quoted_identifiers: true

실제로 쿼리에서 엔티티 클래스, 칼럼 등이 백틱으로 감싸져있는 것을 확인할 수 있다.

...
    alter table `user_account` 
       add constraint `UKbb9h41509tqkio74nclqsegke` unique (`email`)
Hibernate: 
    
    alter table `user_account` 
       drop index `UKrxh9kdyohy2fwn4v3c9mg4i21`
Hibernate: 
...

만약 @Query 어노테이션을 사용하여 직접 쿼리문을 작성할 때에는 직접 백틱으로 감싸줘야 한다.

ddl-auto 옵션

예약어와 겹치지 않게 필드명을 바꿔봐도 계속 WARN으로 위의 에러문구가 떴었다.

원인은 별거 아니었다.
내가 설정해둔 JPA 옵션에 따라 애플리케이션 실행될 때마다 테이블들을 drop 이후에 create 하는데, 이 과정에서 존재하지 않는 외래키를 삭제하려고 하니 에러가 발생하는 것이었다. (이 부분에 대해서는 예외처리가 되어있지 않았던 것 같다.)

https://blog.jiniworld.me/129

  • spring.jpa.properties.hibernate.hbm2ddl.auto
    • none : 아무 동작 하지 않습니다.
    • create-only : 테이블이 없을 경우 create합니다.
    • drop : 테이블을 drop 합니다.
    • create : 기존에 테이블이 존재할 경우 테이블 drop후 새로 create합니다.
    • create-drop : 앱 실행시 테이블 create하고 앱 종료시 테이블을 drop합니다.
    • validate : 엔티티 설정과 기존 테이블 설정이 다를 경우 에러 발생합니다.
    • update : 테이블, 컬럼정보가 달라졌을 경우 추가됩니다.

아직 개발 단계여서 create로 설정해두고 있었는데, drop을 하는 과정에서 문제가 발생했던 것 같다. update로 옵션을 변경해주면 더 이상 위의 메세지가 뜨지 않는다.

외래키를 삭제하는 과정에서 문제가 발생해도 테이블을 다시 생성하는데에는 문제가 없기 때문에 당분간은 해당 메세지를 무시해야할 것 같다.

해결

Entity의 rate, status 등의 필드명을 적절하게 수정해주니 문제가 해결되었다.

그리고 위에서 언급한 내용을 적용했음에도 WARNING 또는 ERROR가 발생해서 직접 테이블들을 전부 날려줬더니 해결된 경우도 있었다.

참고링크

profile
일단 해보자

1개의 댓글

comment-user-thumbnail
2023년 7월 27일

좋은 정보 얻어갑니다, 감사합니다.

답글 달기