在 Liquibase 執行之前建立 PostgreSQL 架構
一、簡介
在資料庫管理領域,確保模式變更的一致性和可追溯性是維護資料完整性和應用程式可靠性的良好實踐。 Liquibase 是一種廣泛採用的資料庫模式變更管理工具,可協助我們跨各種環境無縫地進行版本控制和追蹤資料庫變更。
然而,隨著應用程式變得越來越複雜,有效地組織資料庫物件變得勢在必行。雖然 PostgreSQL 預設使用public
模式,但最佳實踐提倡將特定於應用程式的實體隔離到專用模式。
在本教程中,我們將深入研究在自訂模式中執行 Liquibase 以及如何應對在 Liquibase 執行之前創建 PostgreSQL 模式的挑戰。此外,我們將使用連接到 PostgreSQL 資料庫的簡單 Spring Boot 應用程式來示範它。
2. 液體鹼
Liquibase 用作管理資料庫架構變更的解決方案。它幫助我們在從開發到生產的各個階段更快、更安全地修訂和部署資料庫修改。
它使用 SQL、XML、JSON 和 YAML更改日誌檔案按順序列出資料庫變更。資料庫變更被命名為Changesets 。變更集又包含變更類型,這些變更類型是套用於資料庫的操作,例如建立資料表或新增資料列。 Liquibase 將所有應用的變更儲存在資料庫中,以確定在請求架構更新時應套用哪些新變更。
3. 應用程式設定
首先,我們需要設定一個簡單的 Spring Boot 應用程序,該應用程式使用 PostgreSQL 作為資料庫引擎並使用 Liquibase 來產生表。我們將選擇 Java 17 和 Spring Boot 3,因為稍後我們將需要它們作為第三方函式庫。
3.1. Maven 依賴項
讓我們開始透過新增[spring-boot-starter-web](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web)
、 [spring-boot-started-data-jpa](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa)
、 [liquibase-core](https://mvnrepository.com/artifact/org.liquibase/liquibase-core)
和[postgresql](https://mvnrepository.com/artifact/org.postgresql/postgresql)
依賴項來設定我們的應用程式:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.2.3</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>4.26.0</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.2</version>
<scope>runtime</scope>
</dependency>
3.2. PostgreSQL 配置
現在,我們需要在application.properties
檔案中添加一些屬性以使用 PostgreSQL 作為資料庫:
spring.datasource.url=jdbc:postgresql://some-postgresql-host/some-postgresql-database
spring.datasource.username=your-postgresql-username
spring.datasource.password=your-postgresql-password
請注意,我們需要將這些屬性替換為與我們的環境相符的正確值。
3.3.實體
接下來,讓我們模擬一個用戶管理的應用程式。讓我們先定義一個簡單的User
實體:
@Entity
@Table(name = "users")
public class User {
@Id
private Long id;
private String name;
// standard getters and setters
}
3.4. Liquibase 變更日誌
接下來,我們將使用 Liquibase 在啟動時建立資料庫表。為此,我們需要建立一個變更日誌檔案:
<?xml version="1.0" encoding="utf-8"?>
<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.4.xsd">
<changeSet id="1" author="unknown">
<createTable tableName="users">
<column name="id" type="bigint">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog>
在application.properties
檔案中,我們需要向 Liquibase 指定要使用哪個 Changelog 檔案:
spring.liquibase.change-log=classpath:liquibase/changelog.xml
如果我們運行我們的應用程序,我們將看到Changelog
中指定的Changeset
已被應用,並且在public
模式中創建了三個表**。**這包括我們的users
表和 Liquibase 自動建立的兩個表: databasechangelog
和databasechangeloglock
。
4. 在個人化模式中操作 Liquibase
正如我們在本文開頭所提到的,首選方法是在自訂模式中操作 Liquibase 。這使得管理資料庫物件的組織變得更好、更清晰。此外,自訂模式提供一定程度的隔離和關注點分離,允許應用程式的不同元件或模組獨立運作。
為了解決我們的範例,讓我們假設我們的使用者管理應用程式已成為某種 Modulith :我們現在負責與使用者相關的其他事務,例如權限。因此,我們將受益於使用不同的模式來區分每個概念。
預設情況下,Liquibase 在public
模式下運作。要改變這一點,我們需要覆寫application.properties
檔案中的default-schema
屬性:
spring.liquibase.default-schema=user_management
這種方法導致 Liquibase 完全在the user_management
模式中運行,而databasechangelog
和databasechangeloglock
表也在我們的自訂模式中建立。
另一種方法是修改我們的變更集,指定在那裡建立表格的模式:
<changeSet id="1" author="unknown">
<createTable tableName="users" schemaName="user_management">
<column name="id" type="bigint">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
這種方法將導致在public
模式中建立databasechangelog
和databasechangeloglock
表,而在user_management
模式中建立users
表。
然而,這兩種方法的共同缺點是,在 Liquibase 執行遷移之前,架構必須已經存在。如果我們的目標架構不存在,我們的應用程式將不會啟動。在以下部分中,我們將探討在 Liquibase 執行之前創建 PostgreSQL 模式的一些解決方案。
5. 在 Liquibase 執行之前建立 PostgreSQL 架構
5.1.自訂變更集
儘管 Liquibase 沒有用於創建模式的捆綁更改類型,但我們仍然可以使用sql
標籤包含它。因此,我們將為這個用例建立一個新的變更日誌,名為changelog-customChangeset.xml
,新增一個Changeset
來建立我們想要的目標模式:
<?xml version="1.0" encoding="utf-8"?>
<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.4.xsd">
<changeSet id="0" author="unknown">
<sql>
CREATE SCHEMA IF NOT EXISTS user_management;
</sql>
</changeSet>
<changeSet id="1" author="unknown">
<createTable tableName="users" schemaName="user_management">
<column name="id" type="bigint">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="name" type="varchar(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog>
此解決方案與設定 Liquibase 的預設架構不相容,因為將在建立特定於 Liquibase 的兩個表後執行變更集。因此, databasechangelog
和databasechangeloglock
表仍將放置在public
模式中。
5.2.春豆
為了能夠覆蓋 Liquibase 的預設架構,我們需要確保架構已經存在。一種選擇是建立一個 SchemaInitializer 元件,該元件在DataSource
bean SchemaInitializer
後建立我們的架構:
@Component
public class SchemaInitializer implements BeanPostProcessor {
@Value("${spring.liquibase.default-schema}")
private String schemaName;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DataSource) {
DataSource dataSource = (DataSource) bean;
try {
Connection conn = dataSource.getConnection();
Statement statement = conn.createStatement();
statement.execute(String.format("CREATE SCHEMA IF NOT EXISTS %s", schemaName));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return bean;
}
}
5.3.預液基
Pre-Liquibase是一個模組,允許我們在執行 Liquibase 變更集之前執行一些 SQL 腳本。通常,它用於建立資料庫架構或資料庫目錄。
由於它是 Spring Boot 自動配置模組,因此我們只需要在 Liquibase 執行之前添加依賴項和我們想要執行的 SQL 腳本。該**模組至少需要 Java 17 和 Spring Boot 3.1。**
要使用此模組,我們將繼續新增preliquibase-spring-boot-starter
依賴項:
<dependency>
<groupId>net.lbruun.springboot</groupId>
<artifactId>preliquibase-spring-boot-starter</artifactId>
<version>1.5.0</version>
</dependency>
Pre-Liquibase 具有內建平台自動偵測功能。在偵測資料庫平台後,它決定要執行哪個SQL腳本,因此我們需要將腳本命名為postgresql.sql
。
讓我們看看腳本的內容:
CREATE SCHEMA IF NOT EXISTS user_management;
六,結論
正如我們在整篇文章中了解到的,有多種方法可以在個人化架構中運行 Liquibase 並在 Liquibase 執行之前創建它。透過利用自訂模式,我們可以增強資料庫物件的組織、存取控制和隔離,從而實現更具可擴展性和可維護性的應用程式。
與往常一樣,原始碼可以在 GitHub 上取得。