๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring

Spring Boot 3 + JPA๋ฅผ ํ™œ์šฉํ•œ Liquibase ์‹ค์Šตํ•˜๊ธฐ (1)

by ํ‘์‹œ๋ฐ” 2023. 5. 14.

๐Ÿ“– ์‹ค์Šต ๋‚ด์šฉ

 

1. Spring Boot 3 + Spring Data JPA ํ™˜๊ฒฝ์—์„œ Liquibase ํ™˜๊ฒฝ์„ ์„ค์ •ํ•œ๋‹ค.

2. Entity ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ ๋’ค, ๋กœ์ปฌ DB์™€ ์Šคํ‚ค๋งˆ ์ฐจ์ด์— ๋Œ€ํ•œ ChangeLog ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค. (diff)

3. Liquibase๋ฅผ ํ†ตํ•ด ChangeLog ํŒŒ์ผ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ์šฉํ•˜๊ณ  ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•œ๋‹ค.

4. profile ์„ค์ •์„ ํ†ตํ•ด ๊ฐœ๋ฐœ ํ™˜๊ฒฝ๋ณ„๋กœ ์ ์šฉํ•œ๋‹ค.

 

๐Ÿ“– ์‹ค์Šต 1. Liquibase ํ™˜๊ฒฝ ์„ค์ •ํ•˜๊ธฐ

๊ธฐ๋ณธ ์‹ค์Šต ํ™˜๊ฒฝ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

1. Spring Boot 3.0.6

2. Maven 3.8.4

3. Java 17

4. MariaDB 10.6

1. Liquibase Dependency ์ถ”๊ฐ€

Liquibase๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ liquibase-core ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

์Šคํ”„๋ง์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ liquibase ๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ํ•ด์ฃผ๋ฏ€๋กœ <version>์„ ์ง์ ‘ ์ž…๋ ฅํ•  ํ•„์š”๋Š” ์—†๋‹ค.

ํŠน์ • ๋ฒ„์ „ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ๋”ฐ๋กœ ๋ฒ„์ „์„ ์ž…๋ ฅํ•ด๋„ ์ƒ๊ด€์—†๋‹ค.

 

<dependency>
	<groupId>org.liquibase</groupId>
	<artifactId>liquibase-core</artifactId>
</dependency>

2. Maven Plugin ์ถ”๊ฐ€

liquibase-maven-plugin๋„ ์Šคํ”„๋ง์—์„œ ๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— <version>์„ ์ž…๋ ฅํ•  ํ•„์š”๋Š” ์—†๋‹ค.

 

<plugin>
	<groupId>org.liquibase</groupId>
	<artifactId>liquibase-maven-plugin</artifactId>
	<configuration>
		<diffChangeLogFile>src/main/resources/db/changelog/diff/${maven.build.timestamp}_changelog.xml</diffChangeLogFile>
		<verbose>true</verbose>
		<logging>info</logging>
		<propertyFile>src/main/resources/liquibase.properties</propertyFile>
	</configuration>
	<dependencies>
		<dependency>
			<groupId>org.liquibase.ext</groupId>
			<artifactId>liquibase-hibernate6</artifactId>
			<version>4.20.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
			<version>3.0.6</version>
		</dependency>
	</dependencies>
</plugin>

 

<configuration>์—์„œ liquibase ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ™˜๊ฒฝ ๋ฐ ๋Œ€์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ™˜๊ฒฝ์„ ์„ค์ •ํ•œ๋‹ค.

 

<propertyFile>๋Š” ๋ณ„๋„์˜ ์„ค์ •ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

์„ค์ • ํŒŒ์ผ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๋Œ€์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.

์ฐธ๊ณ ๋กœ, ๊ผญ ์„ค์ • ํŒŒ์ผ์„ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†๋‹ค. ์˜ต์…˜์„ ์ง์ ‘ ์ž…๋ ฅํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ์˜ˆ์‹œ์ฒ˜๋Ÿผ ์ผ๋ถ€ ์˜ต์…˜๋งŒ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค.

 

<diffChangeLogFile>์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋น„๊ตํ•œ ๊ฒฐ๊ณผ๋ฌผ์„ ์–ด๋””์—๋‹ค ์ €์žฅํ• ์ง€ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

๊ฒฝ๋กœ ์ค‘์— ${maven.build.timestamp}๋Š” diff ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋Š” ์‹œ๊ฐ„์œผ๋กœ ์ด๋ฆ„์„ ์„ค์ •ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

 

๋™์ผํ•œ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, diff๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ•˜๋Š” ๊ฒฝ์šฐ ๋™์ผํ•œ ๋‚ด์šฉ์ด ๊ฐ™์€ ํŒŒ์ผ์— ๊ณ„์†ํ•ด์„œ ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ์Œ์„ ์ฃผ์˜ํ•˜์ž.

 

์˜ˆ๋ฅผ ๋“ค์–ด, diff ๋ช…๋ น์„ ํ†ตํ•ด ํ…Œ์ด๋ธ” 2๊ฐœ๋ฅผ ์ƒ์„ฑํ•˜๋Š” changeLog ํŒŒ์ผ์„ ์ƒ์„ฑํ–ˆ์„ ๋•Œ, update๋ฅผ ํ•˜์ง€ ์•Š๊ณ  ๋‹ค์‹œ diff ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ํ…Œ์ด๋ธ” 2๊ฐœ๋ฅผ ์ƒ์„ฑํ•˜๋ผ๋Š” ๋‚ด์šฉ์ด ๊ฐ™์€ ํŒŒ์ผ์— ๋ฐ˜๋ณตํ•ด์„œ ๋“ค์–ด๊ฐ„๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

 

<dependencies>์—๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

๊ธฐ์กด ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์ด ์žˆ๋Š”๋ฐ 'DB to DB'๊ฐ€ ์•„๋‹Œ ์˜ˆ์‹œ์ฒ˜๋Ÿผ 'DB to Entity'์— liquibase๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ์—๋Š” Entity ํŒŒ์ผ์—์„œ ์‚ฌ์šฉ ์ค‘์ธ ์™ธ๋ถ€ ์˜์กด์„ฑ์„ ๋ชจ๋‘ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์„ ์ฃผ์˜ํ•˜์ž.

 

์˜ˆ๋ฅผ ๋“ค์–ด, Entity ํŒŒ์ผ์— @NotNull ๋“ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ๊ด€๋ จ ์˜์กด์„ฑ์ธ javax-validation์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

 

'DB to Entity'๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๋ฐ˜๋“œ์‹œ liquibase-hibernate๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

(๋งŒ์•ฝ, 'DB to DB'๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ํ•ด๋‹น ์˜์กด์„ฑ์€ ํ•„์š” ์—†๋‹ค.)

 

์ฐธ๊ณ ๋กœ, ๋ฌด์กฐ๊ฑด liquibase-hibernate6์„ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

 

์ตœ์‹  JPA ๋ฒ„์ „์—์„œ๋Š” Hibernate 6์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋ฒ„์ „์— ๋งž๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๋งŒ์•ฝ ํ™˜๊ฒฝ์ด Hibernate 5๋ผ๋ฉด ๊ทธ์— ๋งž์ถฐ์„œ liquibase-hibernate5๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

3. liquibase.properties ํŒŒ์ผ ์„ค์ •ํ•˜๊ธฐ

ํ•ด๋‹น ์„ค์ •์€ MariaDB ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ์„ค์ •๋˜์—ˆ๋‹ค.

๋‹ค๋ฅธ DB๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” url, username, password, driver, referenceUrl ์ค‘ dialect ๋ถ€๋ถ„์„ ์•Œ๋งž๊ฒŒ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.

 

changeLogFile=src/main/resources/db/changelog/db.changelog-master.xml
url=jdbc:mariadb://{db ip}:{db port}/{database name}
username={db username}
password={db password}
driver=org.mariadb.jdbc.Driver
referenceUrl=hibernate:spring:com.shibaholic.blogliquibase.model?dialect=org.hibernate.dialect.MariaDBDialect

 

changeLogFile์€ db.changelog-master.xml ํŒŒ์ผ์ด ์–ด๋”” ์žˆ๋Š”์ง€ ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

referenceUrl์—์„œ hibernate:spring: ๋’ค com.shibaholic.blogliquibase.model ์€ ์—”ํ‹ฐํ‹ฐ ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ์ด๋‹ค.

๋ณธ์ธ ํ”„๋กœ์ ํŠธ์— ์„ค์ •ํ•œ ์—”ํ‹ฐํ‹ฐ ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋œ๋‹ค.

4. db.changelog-master.xml  ํŒŒ์ผ ์ƒ์„ฑํ•˜๊ธฐ

 

<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" >

    <includeAll path="/db/changelog/diff/"></includeAll>

</databaseChangeLog>

 

db.changelog-master.xml ํŒŒ์ผ์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•  ๋Œ€์ƒ ํŒŒ์ผ๋“ค์˜ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•œ๋‹ค.

<includeAll>๋กœ ํŠน์ • ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์„ค์ •ํ•˜์—ฌ ํ•ด๋‹น ํŒŒ์ผ์— ์žˆ๋Š” xml ํŒŒ์ผ ์ „์ฒด๋ฅผ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•  ์ˆ˜๋„ ์žˆ๊ณ ,

<include>๋กœ ํŒŒ์ผ ๊ฐœ๋ณ„ ์„ค์ •๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

5. application.properties ํŒŒ์ผ ์„ค์ •ํ•˜๊ธฐ

application properties์—์„œ๋Š” db.change-master.xml ํŒŒ์ผ ๊ฒฝ๋กœ๋งŒ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

 

spring.liquibase.enabled=true
spring.liquibase.change-log=classpath:/db/changelog/db.changelog-master.xml

 

์ด๊ฒƒ์œผ๋กœ ๊ธฐ๋ณธ์ ์ธ Liquid ์„ค์ •์ด ๋์ด ๋‚ฌ๋‹ค.

 

2ํŽธ์—์„œ Entity ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ ๋’ค, ๋กœ์ปฌ DB์™€ ์Šคํ‚ค๋งˆ ์ฐจ์ด์— ๋Œ€ํ•œ ChangeLog ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  diffํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ณต์œ ํ•˜๊ฒ ๋‹ค.

REFERENCE

https://docs.liquibase.com/concepts/connections/creating-config-properties.html

 

Create and Configure a liquibase.properties File

Create and Configure a liquibase.properties File You can use a defaults file called liquibase.properties to store information that Liquibase needs to connect to a particular database, along with other properties that rarely change. This lets you avoid ente

docs.liquibase.com

https://www.baeldung.com/liquibase-refactor-schema-of-java-app

https://stackoverflow.com/questions/75093751/liquibase-generate-diff-with-springboot-3

 

Liquibase generate diff with Springboot 3

I'm trying to generate liquibase-scripts with liquibase 4.18.0 and Spring Boot 3.0.1. And i'm getting this error: [ERROR] Failed to execute goal org.liquibase:liquibase-maven-plugin:4.18.0:diff (de...

stackoverflow.com

https://docs.liquibase.com/change-types/includeall.html

 

includeAll

includeAll Use the includeAll tag to specify a directory that contains multiple changelog files. It is used within your root changelog file to call on the directory and include all XML, YAML, and JSON files as changelog files, and all SQL files as individu

docs.liquibase.com

๋Œ“๊ธ€