Spring Boot 整合 Liquibase 完整案例
项目结构
spring-boot-liquibase-demo/
├── pom.xml
├── src/main/java/com/example/liquibase/
│ ├── LiquibaseApplication.java
│ ├── controller/
│ │ └── UserController.java
│ ├── entity/
│ │ └── User.java
│ ├── mapper/
│ │ └── UserMapper.java
│ └── service/
│ └── UserService.java
├── src/main/resources/
│ ├── application.yml
│ ├── db/
│ │ ├── changelog/
│ │ │ └── db.changelog-master.yaml
│ │ └── changelog/
│ │ ├── 001-create-user-table.yaml
│ │ ├── 002-add-column.yaml
│ │ └── 003-insert-data.yaml
│ ├── mapper/
│ │ └── UserMapper.xml
│ └── schema.sql (可选,用于初始化数据库)
└── src/test/java/com/example/liquibase/
└── LiquibaseApplicationTests.java
pom.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-liquibase-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-liquibase-demo</name>
<description>Spring Boot Liquibase 整合案例</description>
<properties>
<java.version>17</java.version>
<mybatis-plus.version>3.5.5</mybatis-plus.version>
<mysql.version>8.0.33</mysql.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot JPA (可选,如果使用JPA) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MyBatis Plus (如果使用MyBatis) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Liquibase 核心依赖 -->
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<!-- Liquibase 额外支持 (YAML格式) -->
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- H2 内存数据库 (用于测试,可选) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<!-- Liquibase Maven Plugin -->
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>4.27.0</version>
<configuration>
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
</configuration>
</plugin>
</plugins>
</build>
</project>
主应用类
package com.example.liquibase;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.liquibase.mapper")
public class LiquibaseApplication {
public static void main(String[] args) {
SpringApplication.run(LiquibaseApplication.class, args);
}
}
application.yml 配置
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/liquibase_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
# Liquibase 配置
liquibase:
enabled: true
change-log: classpath:db/changelog/db.changelog-master.yaml
# 生成的数据表前缀
database-change-log-lock-table: DATABASECHANGELOGLOCK
database-change-log-table: DATABASECHANGELOG
# 每次启动时强制更新
drop-first: false
# 是否启用默认的 schema
default-schema: public
# JPA 配置(如果使用)
jpa:
hibernate:
ddl-auto: none # 让 Liquibase 管理数据库结构
show-sql: true
properties:
hibernate:
format_sql: true
# MyBatis Plus 配置(如果使用)
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.liquibase.entity
configuration:
map-underscore-to-camel-case: true
logging:
level:
org.liquibase: INFO
com.example.liquibase: DEBUG
Liquibase Changelog 文件
1 主 Changelog 文件 db.changelog-master.yaml
databaseChangeLog:
# 检查数据库类型,如果是 H2 则使用对应的种类型
- preConditions:
- runningAs:
username: root
# 包含各个子 changelog 文件
- include:
file: classpath:db/changelog/001-create-user-table.yaml
- include:
file: classpath:db/changelog/002-add-column.yaml
- include:
file: classpath:db/changelog/003-insert-data.yaml
- include:
file: classpath:db/changelog/004-add-index.yaml
2 创建用户表 001-create-user-table.yaml
databaseChangeLog:
- changeSet:
id: 001-create-user-table
author: admin
changes:
- createTable:
tableName: user
remarks: 用户表
columns:
- column:
name: id
type: BIGINT
autoIncrement: true
constraints:
primaryKey: true
nullable: false
primaryKeyName: pk_user_id
remarks: 主键ID
- column:
name: username
type: VARCHAR(50)
constraints:
nullable: false
unique: true
remarks: 用户名
- column:
name: email
type: VARCHAR(100)
constraints:
nullable: false
unique: true
remarks: 邮箱
- column:
name: password
type: VARCHAR(255)
constraints:
nullable: false
remarks: 密码
- column:
name: phone
type: VARCHAR(20)
remarks: 手机号
- column:
name: status
type: TINYINT
defaultValueNumeric: 1
remarks: 状态(1-正常,0-禁用)
- column:
name: created_at
type: TIMESTAMP
defaultValueComputed: CURRENT_TIMESTAMP
remarks: 创建时间
- column:
name: updated_at
type: TIMESTAMP
defaultValueComputed: CURRENT_TIMESTAMP
remarks: 更新时间
3 添加新列 002-add-column.yaml
databaseChangeLog:
- changeSet:
id: 002-add-column
author: admin
changes:
- addColumn:
tableName: user
columns:
- column:
name: avatar_url
type: VARCHAR(500)
remarks: 头像URL
- column:
name: age
type: INT
remarks: 年龄
- addNotNullConstraint:
tableName: user
columnName: age
columnDataType: INT
defaultNullValue: 0
constraintName: ck_user_age_not_null
4 插入初始数据 003-insert-data.yaml
databaseChangeLog:
- changeSet:
id: 003-insert-data
author: admin
changes:
- insert:
tableName: user
columns:
- column: { name: username, value: "admin" }
- column: { name: email, value: "admin@example.com" }
- column: { name: password, value: "$2a$10$E0DqKkXrHGzL7lUaBmHnUeGdK5C3wjJYr9O1zNmF8bVkFwYxUyTiW" }
- column: { name: phone, value: "13800138000" }
- column: { name: status, valueNumeric: 1 }
- column: { name: avatar_url, value: "https://example.com/avatar.png" }
- column: { name: age, valueNumeric: 30 }
- insert:
tableName: user
columns:
- column: { name: username, value: "test_user" }
- column: { name: email, value: "test@example.com" }
- column: { name: password, value: "$2a$10$E0DqKkXrHGzL7lUaBmHnUeGdK5C3wjJYr9O1zNmF8bVkFwYxUyTiW" }
- column: { name: phone, value: "13900139000" }
- column: { name: status, valueNumeric: 1 }
- column: { name: avatar_url, value: null }
- column: { name: age, valueNumeric: 25 }
5 添加索引 004-add-index.yaml
databaseChangeLog:
- changeSet:
id: 004-add-index
author: admin
changes:
- createIndex:
tableName: user
indexName: idx_user_email
unique: true
columns:
- column:
name: email
- createIndex:
tableName: user
indexName: idx_user_status
unique: false
columns:
- column:
name: status
实体类(使用 JPA)
package com.example.liquibase.entity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "user")
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String password;
private String phone;
private Integer status;
@Column(name = "avatar_url")
private String avatarUrl;
private Integer age;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
Controller 和 Service
package com.example.liquibase.controller;
import com.example.liquibase.entity.User;
import com.example.liquibase.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> getAllUsers() {
return userService.findAll();
}
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping
public User createUser(@RequestBody User user) {
return userService.save(user);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.save(user);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteById(id);
}
}
package com.example.liquibase.service;
import com.example.liquibase.entity.User;
import com.example.liquibase.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> findAll() {
return userRepository.findAll();
}
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User save(User user) {
return userRepository.save(user);
}
public void deleteById(Long id) {
userRepository.deleteById(id);
}
}
Liquibase 常用配置和属性文件
1 liquibase.properties 文件
# 数据库连接配置 url=jdbc:mysql://localhost:3306/liquibase_demo username=root password=your_password # Liquibase 配置 changeLogFile=classpath:db/changelog/db.changelog-master.yaml # 日志级别 logLevel=INFO # 上下文 contexts=dev,prod # 标签 labels=test
2 不同环境配置
# application-dev.yml
spring:
liquibase:
contexts: dev
change-log: classpath:db/changelog/db.changelog-master.yaml
# application-prod.yml
spring:
liquibase:
contexts: prod
change-log: classpath:db/changelog/db.changelog-prod.yaml
高级功能示例
1 使用 SQL 格式的 changelog
005-custom-sql.yaml:

databaseChangeLog:
- changeSet:
id: 005-custom-sql
author: admin
changes:
- sql:
sql: |
ALTER TABLE user
ADD COLUMN last_login_date TIMESTAMP;
- sqlFile:
path: classpath:db/sql/update-user.sql
splitStatements: true
stripComments: true
2 使用存储过程和视图
006-create-view.yaml:
databaseChangeLog:
- changeSet:
id: 006-create-view
author: admin
changes:
- createView:
viewName: v_user_info
selectQuery: |
SELECT u.id, u.username, u.email, u.status
FROM user u
WHERE u.status = 1
replaceIfExists: true
测试配置(使用 H2 内存数据库)
# src/test/resources/application-test.yml
spring:
datasource:
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
username: sa
password:
driver-class-name: org.h2.Driver
liquibase:
enabled: true
change-log: classpath:db/changelog/db.changelog-master.yaml
jpa:
hibernate:
ddl-auto: none
database-platform: org.hibernate.dialect.H2Dialect
十一、Maven 命令
# 运行 Liquibase 命令 mvn liquibase:status # 查看变更状态 mvn liquibase:update # 执行变更 mvn liquibase:rollback # 回滚变更 mvn liquibase:validate # 验证 changelog mvn liquibase:clearCheckSums # 清除校验和 # 启动应用 mvn spring-boot:run # 打包并启动 mvn clean package java -jar target/spring-boot-liquibase-demo-0.0.1-SNAPSHOT.jar
十二、最佳实践建议
-
使用规范化命名:changelog 文件按日期或序号命名,如
20240101-001-create-table.yaml -
只增不改:已经执行过的 changeSet 不要修改内容,如果要修改请创建新的 changeSet
-
使用上下文和环境:通过
contexts和labels控制不同环境执行的 changelog -
添加验证条件:使用
preConditions和validate保证数据一致性 -
使用变量和模板:可以通过 语法使用环境变量
-
版本控制:将 changelog 文件纳入版本控制,保持变更历史清晰
-
测试:在测试环境先行验证 changelog 脚本的正确性
-
文档:每个 changeSet 添加清晰的
remarks说明
databaseChangeLog:
- changeSet:
id: 20240101-001-create-user-table
author: admin
remarks: 创建用户表
changes:
- createTable: ...
这个案例展示了 Spring Boot 与 Liquibase 的完整整合方案,包括数据库版本管理、自动更新、回滚等核心功能,记得根据实际项目需求调整配置和目录结构。