Preconditions in Liquibase
1. 개요
Liquibase는 데이터베이스 변경 사항을 추적하고 배포하는 쉬운 방법을 제공하는 강력한 데이터베이스 관리 도구입니다. 또한 배포 시점에 변경 세트의 동작을 설명할 수 있도록 메타데이터를 제공합니다.
사전 조건은 변경 로그 또는 개별 변경 세트의 실행을 제어하는 데 일반적으로 사용되는 메타데이터의 한 형태입니다. 이들은 배포가 계속되기 전에 특정 요구 사항이 충족되었는지 확인합니다.
이 튜토리얼에서는 사전 조건을 살펴보고 변경 세트 배포 중 제어를 최적화하기 위해 조건부 논리 및 오류 처리 정의 방법을 배웁니다.
2. 사전 조건 이해하기
사전 조건은 Liquibase의 필수 기능입니다. 이들은 변경 세트를 적용하거나 변경하기 전에 충족해야 하는 특정 조건을 정의할 수 있게 합니다. 따라서 사전 조건은 데이터베이스 변경의 수호자라고 생각할 수 있습니다.
Liquibase는 변경 세트를 배포하기 전에 이러한 조건을 체계적으로 평가합니다. 조건이 충족되지 않으면 Liquibase는 변경 세트의 실행을 방지합니다. 사전 조건의 동작에 따라 실패 또는 경고를 발생시키거나 변경 세트를 건너뛸 수 있습니다. 이 메커니즘은 데이터베이스 상태가 요구되는 기준을 충족할 때만 변경 사항이 적용되도록 보장합니다. 이렇게 하면 문제나 오류의 위험을 최소화하면서 배포를 엄격하게 제어할 수 있습니다.
실제로 Liquibase 사전 조건이 유용할 수 있는 몇 가지 시나리오를 살펴보겠습니다:
- 특정 데이터베이스 유형, 데이터베이스 유형 그룹 또는 특정 버전으로 변경을 제한할 수 있습니다.
- 데이터베이스에 객체가 이미 존재하는지 확인하고, 존재 시 생성이나 수정을 피할 수 있습니다.
- 되돌릴 수 없는 변경을 수행하기 전에 기존 데이터를 확인하는 것이 합리적입니다. 예를 들어, 데이터가 여전히 포함된 경우에 테이블을 삭제(dropTable)하도록 방지할 수 있습니다.
- 마지막으로, 변경을 수행하기 전에 특정 데이터의 존재 여부를 확인할 수 있습니다. 예를 들어, 마이그레이션이 구성 테이블에 새로운 행을 삽입하는 경우, 이 행이 이미 존재하지 않는지 확인하여 중복이나 불일치를 피할 수 있습니다.
이러한 관행은 배포를 안전하게 하고 잠재적인 문제를 보다 잘 예측하는 데 도움이 됩니다.
3. 사전 조건 구문 정의하기
사전 조건은 변경 사항 실행을 제어하기 위해 변경 로그 파일에 직접 추가하는 태그입니다. 이제 그 구문에 대해 이야기해 보겠습니다.
3.1. 사전 조건의 기본 구문
간단한 예제를 사용하여 시작해 보겠습니다:
<preConditions>
<dbms type="mysql,oracle" />
</preConditions>
여기서는 dbms 사전 조건을 사용했습니다. 이는 데이터베이스가 MySQL 또는 Oracle 중 하나임을 보장합니다.
Liquibase는 우리의 요구에 맞는 여러 사전 조건 태그를 제공합니다. 사전 조건의 몇 가지 예는 다음과 같습니다:
- dbms는 데이터베이스 유형을 확인합니다.
- runningAs는 데이터베이스 사용자 이름을 확인합니다.
- tableExists는 테이블 존재 여부를 확인합니다.
- columnExists는 특정 열의 존재를 보장합니다.
- foreignKeyExists는 외래 키 존재 여부를 확인합니다.
- sqlCheck는 SQL 쿼리를 실행하고 예상 결과와 비교합니다.
사전 조건은 XML, YAML 또는 JSON과 같은 다양한 변경 로그 파일 형식으로 정의할 수 있습니다. Liquibase 4.27.0 이전에는 sqlCheck만 포맷 SQL과 호환되었습니다. 버전 4.27.0부터는 tableExists 및 viewExists와 같은 다른 사전 조건도 SQL 변경 로그를 지원합니다.
이는 SQL 변경 로그로 작업하는 것을 선호하는 사용자에게 귀중한 개선 사항입니다.
항상 사용 가능한 사전 조건의 전체 목록 및 해당 속성을 참고할 수 있습니다.
3.2. 중첩 사전 조건
Liquibase는
예를 살펴보겠습니다:
<preConditions>
<or>
<and>
<dbms type="oracle" />
<runningAs username="baeldung" />
</and>
<and>
<dbms type="mysql" />
<runningAs username="baeldung" />
</and>
</or>
</preConditions>
이 예제에서는 데이터베이스가 Oracle이고 데이터베이스 사용자가 baeldung이거나 데이터베이스가 MySQL이고 동일한 사용자임을 확인합니다.
논리 연산자가 지정되지 않으면 Liquibase는 기본적으로 AND 논리를 적용합니다. 또 다른 예를 살펴보겠습니다:
<preConditions>
<tableExists tableName="users"/>
<columnExists tableName="users" columnName="email"/>
</preConditions>
이 경우 두 조건이 모두 충족되어야 합니다: users 테이블이 존재해야 하고 email 열이 있어야 합니다.
Liquibase는 사전 조건에 대해 게으른 평가를 사용합니다. 즉,
4. 전역 대 지역 사전 조건
사전 조건은 두 가지 수준에서 사용할 수 있습니다: 변경 로그 전역에서, 및 각 변경 세트에서 지역적으로.
전역 또는 변경 로그 사전 조건은 변경 세트보다 이전에 변경 로그의 상단에 정의됩니다. 이들은 모든 변경 세트에 적용되며, 데이터베이스 호환성을 보장하는 등의 일반 검사를 수행하는 데 유용합니다:
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<preConditions>
<dbms type="mysql"/>
<runningAs username="baeldung"/>
<sqlCheck expectedResult="9.1.0">
SELECT @@version;
</sqlCheck>
</preConditions>
<changeSet id="BAEL-1000" author="baeldung">
<addColumn tableName="users">
<column name="country" type="varchar(25)"/>
</addColumn>
</changeSet>
<changeSet id="BAEL-1001" author="baeldung">
<addColumn tableName="tutorials">
<column name="code" type="varchar(5)"/>
</addColumn>
</changeSet>
</databaseChangeLog>
이 예제에서는 데이터베이스가 MySQL이며 변경 세트를 배포하는 데이터베이스 사용자가 baeldung인지, 또한 데이터베이스 버전이 9.1.0인지 확인했습니다. 따라서 이러한 조건 중 어느 것도 충족되지 않으면 어떤 변경 세트도 실행되지 않습니다.
지역 사전 조건은 변경 세트의 상단에 정의되며 특정 변경 세트에만 적용됩니다. 이들은 변경을 적용하기 전에 테이블 또는 열이 존재하는지 확인하는 등의 타겟팅된 검사를 가능하게 합니다.
다음과 같은 예를 살펴보겠습니다:
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="BAEL-1000" author="baeldung">
<addColumn tableName="users">
<column name="country" type="varchar(25)"/>
</addColumn>
</changeSet>
<changeSet id="BAEL-1002" author="baeldung">
<preConditions>
<tableExists tableName="users"/>
<columnExists tableName="users" columnName="last_visit"/>
</preConditions>
<dropColumn tableName="users" columnName="last_visit"/>
</changeSet>
</databaseChangeLog>
이 사전 조건은 id BAEL-1002가 있는 변경 세트에만 적용됩니다. 이는 users 테이블과 last_visit 열이 존재해야만 해당 열을 삭제할 수 있도록 보장합니다.
5. 사전 조건의 실패 및 오류 처리
Liquibase는 사전 조건 실패와 실행 중 오류를 구별합니다:
- 실패는 사전 조건이 성공적으로 실행되었지만 예상 기준을 충족하지 않을 때 발생합니다.
- 오류는 구문 오류와 같은 기술적인 문제로 인해 사전 조건 실행을 방해할 때 발생합니다.
onFail 및 onError 속성을 사용하여 사전 조건 검사의 실패 또는 오류를 처리하는 방법을 지정합니다.
5.1. onFail 및 onError 속성
사전 조건이 포함된 변경 세트의 변경 로그 예제를 살펴보겠습니다:
<changeSet id="BAEL-1003" author="baeldung">
<preConditions onFail="HALT" onError="HALT">
<not>
<columnExists tableName="users" columnName="verified"/>
</not>
</preConditions>
<addColumn tableName="users">
<column name="verified" type="boolean" defaultValue="false"/>
</addColumn>
</changeSet>
이 변경 로그를 mvn liquibase:update 명령으로 실행할 수 있습니다.
verified 열이 이미 존재하는 경우, 사전 조건이 실패하여 다음 메시지가 발생합니다:
Not precondition failed
예를 들어, users 테이블이 존재하지 않으면 오류가 발생합니다:
liquibase.exception.DatabaseException: Table 'baeldung_liquibase.users' doesn't exist
두 경우 모두 HALT 값은 실패 또는 오류가 발생할 경우 즉시 실행을 중단합니다.
5.2. onFail 및 onError 속성에 대한 값
사전 조건을 처리하는 다양한 동작을 구성할 수 있습니다:
- HALT는 변경 로그 실행을 즉시 중단합니다. 이는 기본 동작입니다.
- WARN은 경고를 기록하지만 실행을 계속합니다.
- MARK_RAN은 DATABASECHANGELOG 테이블에서 변경 세트를 실행된 것으로 표시하고 계속 진행합니다.
- CONTINUE는 변경 세트를 건너뛰고 실행을 진행합니다.
다음 표는 가능한 값의 요약입니다:
onFail 속성 값 | onError 속성 값 | |
---|---|---|
전역 사전 조건 | HALT, WARN | HALT, WARN |
지역 사전 조건 | HALT, CONTINUE, MARK_RAN, WARN | HALT, CONTINUE, MARK_RAN, WARN |
추가 속성인 onErrorMessage 및 onFailMessage는 사용자 정의 오류 또는 실패 메시지를 가능하게 합니다:
<preConditions onFail="WARN" onFailMessage="Column verified already exists">
<not>
<columnExists tableName="users" columnName="verified"/>
</not>
</preConditions>
이러한 속성은 유연성을 제공하고 사전 조건을 처리할 때 사용자 정의 동작을 가능하게 합니다.
6. 결론
이 기사에서는 Liquibase 사전 조건이 데이터베이스 업데이트 동안 제어 및 정밀성을 향상시키는 방법을 살펴보았습니다. 이들은 변경을 적용하기 전에 데이터베이스가 특정 조건을 충족하는지 확인합니다. 이러한 접근 방식은 위험을 줄이고 잠재적 오류를 피하는 데 도움이 됩니다.
사전 조건을 효과적으로 활용하면 배포를 간소화하고 데이터베이스 무결성을 유지할 수 있습니다.
소스 코드는 항상 여기 GitHub에서 확인할 수 있습니다.