트러블슈팅

TestCode 실행 시 liquibase에서 Table "DATABASECHANGELOG" already exists; SQL statement 에러

MJ.Lee 2024. 1. 26. 17:55

문제

Test Code를 돌릴 때 liquibase에서 아래와 같이 'DATABASECHANGELOG" already exists; SQL statement' 라는 에러가 났다.

liquibase로 changelog 중 schema.xml을 만들 때 DATABASECHANGELOG라는 테이블을 포함하지 않았고,

생성된 schema.xml에도 create하는 부분이 없는데 DATABASECHANGELOG 생성을 시도하고 있었다.

원인

DATABASECHANGELOG는 liquibaes에서 사용하고 있는 테이블이고, 없으면 liquibase에서 자동으로 생성한다.

참고(아래 참고 자료에 있음): https://docs.liquibase.com/concepts/tracking-tables/databasechangelog-table.html

 

liquibase에서 DATABASECHANGELOG 테이블을 만들 때, 테이블이 있는 지 없는 지 조사한다.

조사할 때 이미 존재했던 DATABASECHANGELOG 테이블을 발견하지 못하고 다시 생성하려 한 것을 알 수 있다.

 

해결 방법을 찾아보니 아래와 같이 DATABASE_TO_UPPER=false를 h2 db 설정에서 지우라고 했다.

 

애플리케이션 h2 db에 설정된 것을 확인해보니 DATABASE_TO_UPPER=false가 있었다. 

  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=FALSE;MODE=MYSQL
    username:
    password:
    hikari:
      auto-commit: false

 

 

 h2 database의 기본 옵션은 테이블이나 컬럼 이름을 모두 대문자로 생성하는 것이다. 그럼 h2 database 내부적으로 대소문자 구분할 필요가 없기 때문이다.  DATABASE_TO_UPPER=false 옵션은 모두 대문자로 만들지 않고, 테이블이나 컬럼을 대소문자로 구분해서 만든다. 

 

DATABASE_TO_UPPER=false 옵션을 넣음으로써, liquibase는 DATABASECHANGELOG가 소문자일 거라 예상하고 소문자인 databasechangelog로 찾는다. 하지만 로그를 보면 liquibase는 생성할 때 DATABASECHANGELOG를 대문자로 생성한다.

 

내 애플리케이션은 liquibase를 실행할 때 changelog로 schema.xml과 data.xml 2개를 포함한다.

liquibase는 chagelog를 db에 반영하는 작업을 2번 실행하고 이 때마다 DATABASECHANGELOG 테이블 존재 확인 및 생성을 한다.

master.xml

 

즉, 에러가 난 과정은 아래와 같다.

1. schema.xml을 실행한다. 이 때 DATABASECHANGELOG로 대문자로 테이블에 생성된다.

2. data.xml을 실행한다. h2 database의 DATABASE_TO_UPPER=false 옵션으로 인해 databasechangelog로 찾는다. 하지만 생성된 테이블은 DATABASECHANGELOG 대문자라 찾을 수 없다.

3. 다시 DATABASE_TO_UPPER로 테이블 생성을 시도한다.

4. DATABASECHANGELOG" already exists; SQL statement 에러가 발생한다.

 

해결

첫 번째 방법: DATABASE_TO_UPPER=false 옵션 제거

DATABASE_TO_UPPER=false 옵션을 제거하면 모두 대문자로 테이블이 만들어지므로 DATABASECHANGELOG 에러는 사라졌다.

하지만 애플리케이션이 JOOQ를 사용하고 있고, JOOQ로 실행되는 sql 쿼리는 테이블이 소문자이다. H2 Database는 대소문자를 구분하므로 쿼리에 소문자로 된 테이블명은 찾을 수 없다는 에러가 떴다.

 

따라서, application-test.yml에 h2 db 옵션에서 DATABASE_TO_UPPER=false을 제거하고 2개 옵션을 추가했다.

  • DATABASE_TO_LOWER=TRUE: 모든 테이블명과 컬럼명을 소문자로 생성한다.
  • CASE_INSENSITIVE_IDENTIFIERS=TRUE: 대소문자 구분을 하지 않는다.
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
   ## 변경 전
   ## url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=FALSE;MODE=MYSQL
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;MODE=MYSQL    
    username:
    password:
    hikari:
      auto-commit: false

 

 

두 번째 방법: Liquibase에 database-change-log-table, database-change-log-lock-table 설정

DATABASE_TO_UPPER=false 옵션을 제거하지 않고, liquibase에서 생성하는 DATABASECHANGELOG 테이블 이름을 소문자로 지정해줄 수 있다.

 

application-test.yml에 liquibase 설정을 아래와 같이 테이블명을 소문자로 해준다.

  liquibase:
    change-log: classpath:config/liquibase/master.xml
    database-change-log-lock-table: 'databasechangeloglock'
    database-change-log-table: 'databasechangelog'

 

그러면 소문자로 테이블을 생성하고, 찾을 때도 소문자로 찾기 때문에 DATABASECHANGELOG" already exists; SQL statement 에러가 발생하지 않는다.

 

참고 자료

https://stackoverflow.com/questions/23335524/liquibase-error-relation-databasechangelog-already-exists

 

Liquibase - Error : relation "databasechangelog" already exists

I'm trying to integrate liquibase with our application. I'm executing it using Maven integration approach. When I execute, I see that creation script for databasechangelog invoked twice and get "

stackoverflow.com

https://docs.liquibase.com/concepts/tracking-tables/databasechangelog-table.html

 

DATABASECHANGELOG table

DATABASECHANGELOG table Liquibase uses the DATABASECHANGELOG (DBCL) table to track which changesets have been run. If the table does not exist in the database, Liquibase creates one automatically. Columns The table tracks each changeset as a row, identifie

docs.liquibase.com

https://nicolas.riousset.com/category/software-methodologies/case-sensitivity-issue-with-liquibase-databasechangelog-table-name/

 

Case sensitivity issue with liquibase change log table names

While starting a SpringBoot/JHipster MariaDB application, I ran into this Liquibase database update error: liquibase.exception.MigrationFailedException: Migration failed for changeset config/liquib…

nicolas.riousset.com