List All Liquibase SQL Types With Java
1. 소개
이 글에서는 Liquibase가 지원하는 다양한 SQL 데이터 타입을 살펴볼 것입니다. 또한 MySQL, PostgreSQL, Oracle 등 여러 데이터베이스에서 이들이 어떻게 표현되는지 검토하겠습니다.
2. Liquibase란?
Liquibase는 데이터베이스 변경 관리를 위한 오픈 소스 도구로, 데이터베이스 변경 사항을 추적, 버전 관리 및 배포하는 데 도움을 줍니다. Java 애플리케이션에서 데이터베이스 마이그레이션을 자동화하는 데 흔히 사용됩니다. Liquibase를 사용하면 애플리케이션 코드 관리와 같은 방식으로 데이터베이스 변경을 관리할 수 있습니다. 이는 지속적인 통합 및 배포 속도를 높이고 데이터베이스 변경 사항에 대한 버전 관리를 유지하는 데 도움이 됩니다.
2.1. 프로젝트에서 Liquibase 사용하기
프로젝트에서 Liquibase를 사용하려면 먼저 Maven의 pom.xml 파일에 최신 liquibase-core 의존성을 추가해야 합니다:
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>4.27.0</version>
</dependency>
Liquibase는 MySQL, PostgreSQL, Oracle 등 다양한 데이터베이스를 지원합니다. 데이터베이스가 준비되면 liquibase.properties 파일을 사용하여 연결 설정을 정의합니다. properties 파일에는 데이터베이스 호스트 URL, 연결 자격 증명 및 드라이버 정보와 같은 필드가 포함됩니다:
changeLogFile=db/changelog/db.changelog-master.yaml
url=jdbc:mysql://localhost:3306/mydatabase
username=dbuser
password=dbpassword
driver=com.mysql.cj.jdbc.Driver
다음으로 가장 중요한 단계인 changelog 파일을 정의합니다.
2.2. Changelog 파일
changelog 파일은 단일 진실의 출처 역할을 하며, 시간이 지남에 따라 데이터베이스의 변경 이력을 저장합니다. changelog 파일은 SQL, XML, JSON, YAML과 같은 다양한 형식을 가질 수 있습니다.
기존 데이터베이스의 changelog는 Maven으로 자동 생성할 수 있습니다:
mvn liquibase:generateChangeLog
changelog 파일을 더 자세히 살펴보겠습니다. changelog는 각각 식별자(id)를 가진 일련의 changeset으로 구성됩니다. 개별 changeset는 데이터베이스에 대한 개별 수정을 설명합니다. Liquibase는 다음과 같은 다양한 DML 변경을 지원합니다:
- createTable
- addColumn
- dropColumn
- update
- insert
- sql (사용자 정의 SQL 용)
여기 XML로 작성된 changelog의 예가 있습니다:
<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-3.8.xsd">
<changeSet id="1" author="baeldung">
<createTable tableName="baeldung_articles">
<column name="id" type="int">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(255)"/>
</createTable>
</changeSet>
<changeSet id="2" author="baeldung">
<addColumn tableName="baeldung_authors">
<column name="name" type="varchar(255)"/>
</addColumn>
</changeSet>
</databaseChangeLog>
2.3. 개별 Changeset의 구조
개별 changeset 헤더에는 다음과 같은 속성이 포함됩니다:
- id: changeset을 식별하는 데 필요한 필수 속성입니다. 이는 알파벳과 숫자의 조합으로 이루어진 값일 수 있습니다.
- author: changeset 작성자의 식별자가 들어갑니다.
- context: 이 필드는 선택 사항으로, 주로 실행할 환경(개발, 운영)을 지정하는 데 사용됩니다.
- label: 또 다른 선택적 필드로, 변경 사항에 대한 추가 컨텍스트를 제공하는 데 사용될 수 있습니다.
변경 내용은 여러 유형의 데이터베이스 수정을 포함할 수 있습니다. 사용할 수 있는 일반적인 변경 사항은 다음과 같습니다:
- createTable
- addColumn
- dropTable
- insert
Liquibase는 changelog 아래에서 changeset에 대한 트랜잭션 지원을 제공합니다. 따라서 개별 changeset이 실패하면 전체 changelog가 롤백됩니다.
3. Liquibase에서 지원하는 SQL 데이터 타입
Liquibase는 Java에서 다양한 데이터베이스를 지원합니다. 그러나 데이터베이스가 데이터 타입을 다르게 지원한다는 점을 인식하는 것이 중요합니다. 예를 들어, 문자 데이터 타입의 크기와 이름은 여러 데이터베이스에서 다를 수 있습니다. 일부 데이터베이스는 UUID를 기본적으로 지원할 수 있지만 다른 데이터베이스는 문자인형이나 문자열을 사용해 해당 값을 저장해야 할 수 있습니다.
3.1. 데이터 타입의 일관성 필요성
Liquibase는 데이터베이스에 대한 변경 관리 솔루션을 제공합니다. 따라서 Liquibase는 데이터베이스 독립성을 지원해야 합니다. 이것은 Liquibase가 모든 지원되는 데이터베이스에 걸쳐 데이터 유형을 표준화할 수 있을 때만 가능합니다. 단일 changeset은 기본 데이터베이스와 관계없이 실행될 수 있어야 합니다. 개발자는 자신이 작업할 데이터베이스 플랫폼에 대해 크게 걱정하지 않고도 changeset을 작성할 수 있어야 합니다.
3.2. 데이터베이스 독립성
Liquibase는 세 가지 솔루션을 설정하여 진정한 데이터베이스 독립성을 제공합니다:
- 표준화된 데이터베이스: Liquibase는 대부분의 데이터베이스 플랫폼에서 널리 사용되는 데이터 타입의 표준 집합을 정의합니다(int, timestamp, text 등). 개발자는 사용하는 데이터베이스에 대해 걱정하지 않고 이러한 데이터 타입을 자유롭게 사용할 수 있습니다.
- 데이터 타입 자동 변환: Liquibase는 데이터 타입을 플랫폼별로 자동 변환합니다. 예를 들어, Liquibase의 text 타입은 Oracle 데이터베이스에서 자동으로 clob로, SQL Server에서는 varchar로 변환됩니다.
- 구성 가능: Liquibase는 추가 구성 가능한 매개변수인 convert-data-types을 노출합니다. 자동 데이터 타입 변환을 수행하지 않으려는 경우 이 매개변수를 제공합니다. 이 값을 false로 설정하면 목표 데이터베이스에 맞는 정확한 데이터 타입을 제공해야 합니다.
3.3. Liquibase에서 제공하는 데이터 타입
Liquibase는 다음과 같은 여러 SQL 데이터 타입을 기본 제공하고 있습니다:
bigint, blob, boolean, char, clob, currency, datetime, date, decimal, double, float, int, mediumint, nchar, nvarchar, number, smallint, time, timestamp, tinyint, uuid, varchar.
4. 모든 Liquibase 데이터 타입의 변환 차트
Liquibase는 데이터 타입의 자동 변환을 관리합니다. 그러나 개발자가 호스팅 데이터베이스에 따라 데이터 타입이 어떻게 매핑될 수 있는지 이해하는 것은 여전히 좋은 관행입니다. 이 섹션에서는 가장 일반적으로 사용되는 데이터 타입에 대한 포괄적인 매핑 목록을 제공합니다:
Liquibase 데이터 타입 | MySQL | SQLite | H2 | Postgres | DB2 | SQL Server | Oracle |
---|---|---|---|---|---|---|---|
BOOLEAN | BIT(1) | BOOLEAN | BOOLEAN | BOOLEAN | SMALLINT | BIT | NUMBER(1) |
TINYINT | TINYINT | TINYINT | TINYINT | SMALLINT | SMALLINT | TINYINT | NUMBER(3) |
INT | INT | INTEGER | INT | INT | INTEGER | INT | INTEGER |
MEDIUMINT | MEDIUMINT | MEDIUMINT | MEDIUMINT | MEDIUMINT | MEDIUMINT | INT | MEDIUMINT |
BIGINT | BIGINT | BIGINT | BIGINT | BIGINT | BIGINT | BIGINT | NUMBER(38, 0) |
FLOAT | FLOAT | FLOAT | FLOAT | FLOAT | FLOAT | FLOAT(53) | FLOAT |
DOUBLE | DOUBLE | DOUBLE | DOUBLE | DOUBLE PRECISION | DOUBLE | FLOAT(53) | FLOAT(24) |
DECIMAL | DECIMAL | DECIMAL | DECIMAL | DECIMAL | DECIMAL | DECIMAL(18, 0) | DECIMAL |
NUMBER | NUMERIC | NUMBER | NUMBER | NUMERIC | NUMERIC | NUMERIC(18, 0) | NUMBER |
BLOB | LONGBLOB | BLOB | BLOB | BYTEA | BLOB | VARBINARY | BLOB |
FUNCTION | FUNCTION | FUNCTION | FUNCTION | FUNCTION | FUNCTION | FUNCTION | FUNCTION |
DATETIME | DATETIME | TEXT | TIMESTAMP | TIMESTAMP WITHOUT TIME ZONE | TIMESTAMP | DATETIME | TIMESTAMP |
TIME | TIME | TIME | TIME | TIME WITHOUT TIME ZONE | TIME | TIME(7) | DATE |
TIMESTAMP | TIMESTAMP | TEXT | TIMESTAMP | TIMESTAMP WITHOUT TIME ZONE | TIMESTAMP | DATETIME | TIMESTAMP |
DATE | DATE | DATE | DATE | DATE | DATE | DATE | DATE |
CHAR | CHAR | CHAR | CHAR | CHAR | CHAR | CHAR(1) | CHAR |
VARCHAR | VARCHAR | VARCHAR | VARCHAR | VARCHAR | VARCHAR | VARCHAR | VARCHAR2 |
NCHAR | NCHAR | NCHAR | NCHAR | NCHAR | NCHAR | NCHAR(1) | NCHAR |
NVARCHAR | NVARCHAR | NVARCHAR | NVARCHAR | VARCHAR | NVARCHAR | NVARCHAR(1) | NVARCHAR2 |
CLOB | LONGTEXT | TEXT | CLOB | TEXT | CLOB | VARCHAR | CLOB |
CURRENCY | DECIMAL | REAL | DECIMAL | DECIMAL | DECIMAL(19, 4) | MONEY | NUMBER(15, 2) |
UUID | CHAR(36) | TEXT | UUID | UUID | char(36) | UNIQUEIDENTIFIER | RAW(16) |
5. 모든 데이터 타입을 프로그래밍적으로 나열하기
Liquibase와의 호환성을 추출하기 위해 Java 메서드를 사용할 수 있습니다. 먼저 두 개의 리스트를 생성합니다. 첫 번째 리스트는 Liquibase가 지원하는 호환 데이터베이스를 저장합니다:
private static List getDatabases() {
return List.of(
new MySQLDatabase(),
new SQLiteDatabase(),
new H2Database(),
new PostgresDatabase(),
new DB2Database(),
new MSSQLDatabase(),
new OracleDatabase(),
new HsqlDatabase(),
new FirebirdDatabase(),
new DerbyDatabase(),
new InformixDatabase(),
new SybaseDatabase(),
new SybaseASADatabase()
);
}
두 번째 리스트는 검사하려는 데이터타입의 포괄적인 목록을 저장합니다:
private static List<LiquibaseDataType> getDataTypes() {
return List.of(
new BooleanType(),
new TinyIntType(),
new IntType(),
new MediumIntType(),
new BigIntType(),
new FloatType(),
new DoubleType(),
new DecimalType(),
new NumberType(),
new BlobType(),
new DateTimeType(),
new TimeType(),
new TimestampType(),
new DateType(),
new CharType(),
new VarcharType(),
new NCharType(),
new NVarcharType(),
new ClobType(),
new CurrencyType(),
new UUIDType()
);
}
다음으로, 언급된 Liquibase 데이터 타입 (dataTypes) 및 데이터베이스 타입 (databases) 리스트를 순회하고, 각 Liquibase 데이터 타입을 모든 데이터베이스에 대해 데이터베이스 특정 데이터 타입으로 변환하려고 시도합니다. 또한 각 조합에 대해 데이터 타입의 이름과 데이터베이스 특정 타입을 인쇄합니다. 에러 발생 시에도 계속 처리할 수 있도록 예외를 우아하게 처리합니다:
List<LiquibaseDataType> dataTypes = getDataTypes();
List<AbstractJdbcDatabase> databases = getDatabases();
for (LiquibaseDataType dataTypeInstance : dataTypes) {
try {
LiquibaseDataType dataType = dataTypeInstance;
dataType.finishInitialization("");
System.out.println(dataType.getName());
for (AbstractJdbcDatabase databaseInstance : databases) {
try {
Database database = databaseInstance;
String databaseType = dataType.toDatabaseDataType(database)
.toString();
System.out.println(databaseInstance.getName() + ": " + databaseType);
} catch (Exception e) {
System.err.println("Error initializing database class "
+ databaseInstance.getName() + ": " + e.getMessage());
}
}
System.out.println();
} catch (Exception e) {
System.err.println("Error initializing data type class "
+ dataTypeInstance.getName() + ": " + e.getMessage());
}
}
6. 결론
이번 글에서는 Liquibase가 공통 데이터 타입을 제공하고 개발자가 데이터베이스 버전을 관리하는 데 어떻게 도움이 되는지를 살펴보았습니다.
모든 코드 샘플은 GitHub에서 확인할 수 있습니다.