关于数据库迁移


什么是数据库迁移


数据库迁移(Database Migration)是指对数据库结构进行版本控制的过程,它允许开发团队跟踪数据库模式的变更,并确保在不同环境(开发、测试、生产)中数据库结构的一致性。

为什么需要数据库迁移


在传统的软件开发中,数据库变更通常通过手动执行SQL脚本完成,这种方式存在诸多问题:

版本不一致:不同环境的数据库结构可能不一致

协作困难:多人开发时容易产生冲突

回滚复杂:出现问题时难以快速回滚到之前的版本

缺乏历史记录:无法追踪数据库结构的变更历史

Liquibase

Liquibase 是一个开源的数据库迁移工具,它通过 changelog 文件来管理数据库的变更,支持多种格式(XML、JSON、YAML、SQL)的变更定义,能够与多种数据库系统协同工作。

主要特性:

支持多种数据库(MySQL、PostgreSQL、Oracle等)

多种变更定义格式

回滚支持

与Spring Boot无缝集成

丰富的变更类型支持
 

Spring Boot 集成 Liquibase

添加依赖

首先,在 pom.xml 中添加 Liquibase 依赖:

<!-- Liquibase Database Migration -->
        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
        </dependency>

Liquibase比起Flyway,对Springboot的支持更好。使用Springboot3也可以运行,Flyway则在Springboot3里面无法使用。

YML配置

  # Liquibase Configuration
  liquibase:
    enabled: true
    change-log: classpath:db/changelog/db.changelog-master.xml
    drop-first: false
    default-schema: mqtt

定义Liquibase的XML

创建主变更日志文件

在 src/main/resources/db/changelog 目录下创建主变更日志文件 db.changelog-master.yaml

<?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-4.20.xsd">

    <!-- Include all changelog files -->
    <include file="db/changelog/changes/v1.0-initial-schema.xml"/>
    <include file="db/changelog/changes/v1.1-sample-data.xml"/>

</databaseChangeLog>

v1.0-initial-schema.xml 初始化数据库结构

<?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-4.20.xsd">

    <!-- Create mqtt_connection table -->
    <changeSet id="1" author="mqtt-websocket-bridge">
        <createTable tableName="mqtt_connection" remarks="MQTT Connection Table">
            <column name="id" type="BIGINT" autoIncrement="true">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="client_id" type="VARCHAR(255)" remarks="MQTT Client ID">
                <constraints nullable="false" unique="true"/>
            </column>
            <column name="broker_url" type="VARCHAR(255)" remarks="MQTT Broker URL">
                <constraints nullable="false"/>
            </column>
            <column name="username" type="VARCHAR(255)" remarks="Username"/>
            <column name="password" type="VARCHAR(255)" remarks="Password"/>
            <column name="keep_alive" type="INT" defaultValue="60" remarks="Keep Alive Interval (seconds)"/>
            <column name="clean_session" type="TINYINT(1)" defaultValue="1" remarks="Clean Session Flag"/>
            <column name="protocol_version" type="VARCHAR(50)" defaultValue="MQTT 3.1.1" remarks="Protocol Version"/>
            <column name="tls_enabled" type="TINYINT(1)" defaultValue="0" remarks="TLS Enabled"/>
            <column name="status" type="INT" defaultValue="0" remarks="Connection Status (0: disconnected, 1: connected)"/>
            <column name="connected_at" type="DATETIME" remarks="Connection Timestamp"/>
            <column name="disconnected_at" type="DATETIME" remarks="Disconnection Timestamp"/>
            <column name="created_at" type="DATETIME" defaultValueComputed="CURRENT_TIMESTAMP" remarks="Create Time"/>
            <column name="updated_at" type="DATETIME" defaultValueComputed="CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" remarks="Update Time"/>
            <column name="deleted" type="INT" defaultValue="0" remarks="Logical Delete Flag"/>
        </createTable>
        
        <!-- Create indexes for mqtt_connection -->
        <createIndex indexName="idx_client_id" tableName="mqtt_connection">
            <column name="client_id"/>
        </createIndex>
        <createIndex indexName="idx_status" tableName="mqtt_connection">
            <column name="status"/>
        </createIndex>
        <createIndex indexName="idx_created_at" tableName="mqtt_connection">
            <column name="created_at"/>
        </createIndex>
    </changeSet>

    <!-- Create mqtt_subscription table -->
    <changeSet id="2" author="mqtt-websocket-bridge">
        <createTable tableName="mqtt_subscription" remarks="MQTT Subscription Table">
            <column name="id" type="BIGINT" autoIncrement="true">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="client_id" type="VARCHAR(255)" remarks="MQTT Client ID">
                <constraints nullable="false"/>
            </column>
            <column name="topic" type="VARCHAR(500)" remarks="MQTT Topic">
                <constraints nullable="false"/>
            </column>
            <column name="qos" type="INT" defaultValue="0" remarks="Quality of Service (0, 1, 2)"/>
            <column name="subscribed_at" type="DATETIME" defaultValueComputed="CURRENT_TIMESTAMP" remarks="Subscription Timestamp"/>
            <column name="created_at" type="DATETIME" defaultValueComputed="CURRENT_TIMESTAMP" remarks="Create Time"/>
            <column name="updated_at" type="DATETIME" defaultValueComputed="CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" remarks="Update Time"/>
            <column name="deleted" type="INT" defaultValue="0" remarks="Logical Delete Flag"/>
        </createTable>
        
        <!-- Create indexes for mqtt_subscription -->
        <createIndex indexName="idx_client_id" tableName="mqtt_subscription">
            <column name="client_id"/>
        </createIndex>
        <createIndex indexName="idx_topic" tableName="mqtt_subscription">
            <column name="topic"/>
        </createIndex>
        <createIndex indexName="idx_subscribed_at" tableName="mqtt_subscription">
            <column name="subscribed_at"/>
        </createIndex>
        
        <!-- Create unique constraint -->
        <addUniqueConstraint tableName="mqtt_subscription" 
                            columnNames="client_id, topic" 
                            constraintName="uk_client_topic"/>
    </changeSet>

    <!-- Create mqtt_message table -->
    <changeSet id="3" author="mqtt-websocket-bridge">
        <createTable tableName="mqtt_message" remarks="MQTT Message Table">
            <column name="id" type="BIGINT" autoIncrement="true">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="client_id" type="VARCHAR(255)" remarks="MQTT Client ID">
                <constraints nullable="false"/>
            </column>
            <column name="topic" type="VARCHAR(500)" remarks="MQTT Topic">
                <constraints nullable="false"/>
            </column>
            <column name="payload" type="TEXT" remarks="Message Payload"/>
            <column name="qos" type="INT" defaultValue="0" remarks="Quality of Service (0, 1, 2)"/>
            <column name="retained" type="TINYINT(1)" defaultValue="0" remarks="Retained Message Flag"/>
            <column name="direction" type="VARCHAR(50)" remarks="Message Direction (INBOUND, OUTBOUND)">
                <constraints nullable="false"/>
            </column>
            <column name="created_at" type="DATETIME" defaultValueComputed="CURRENT_TIMESTAMP" remarks="Create Time"/>
            <column name="deleted" type="INT" defaultValue="0" remarks="Logical Delete Flag"/>
        </createTable>
        
        <!-- Create indexes for mqtt_message -->
        <createIndex indexName="idx_client_id" tableName="mqtt_message">
            <column name="client_id"/>
        </createIndex>
        <createIndex indexName="idx_topic" tableName="mqtt_message">
            <column name="topic"/>
        </createIndex>
        <createIndex indexName="idx_direction" tableName="mqtt_message">
            <column name="direction"/>
        </createIndex>
        <createIndex indexName="idx_created_at" tableName="mqtt_message">
            <column name="created_at"/>
        </createIndex>
    </changeSet>

</databaseChangeLog>

v1.1-sample-data.xml 初始化数据

<?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-4.20.xsd">

    <!-- Insert sample connection data -->
    <changeSet id="4" author="mqtt-websocket-bridge">
        <insert tableName="mqtt_connection">
            <column name="client_id" value="emqx_NJEONID"/>
            <column name="broker_url" value="tcp://localhost:1883"/>
            <column name="username" value=""/>
            <column name="password" value=""/>
            <column name="keep_alive" valueNumeric="60"/>
            <column name="clean_session" valueNumeric="1"/>
            <column name="protocol_version" value="MQTT 5"/>
            <column name="status" valueNumeric="0"/>
        </insert>
    </changeSet>

</databaseChangeLog>

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐