zoukankan      html  css  js  c++  java
  • [jOOQ中文]3. 数据库版本管理工具Flyway

    https://segmentfault.com/a/1190000010526452


    在执行数据库迁移时,我们推荐使用jOOQ与Flyway - 数据库迁移轻松。 在本章中,我们将简单的来使用这两个框架。

    一、Flyway简介

    图片描述

    什么是Flyway

    Flyway是独立于数据库的应用、管理、跟踪数据库变更的数据库版本管理工具。
    Flyway的项目主页是:https://flywaydb.org/

    为什么使用Flyway

    • 不同的开发人员在开发产品特性时,都有可能更新数据库(添加新表,新的约束等)。当开发人员完成工作并提交代码时,代码会被合并到主分支并在测试服务器上执行单元测试与集成测试。我们在哪个环节来执行数据库的更新操作呢?由QA 部门手工执行sql 脚本?或者我们开发一断程序自动执行数据库更新?以什么顺序来执行这些更新脚本?这些问题同样存在于生产环境。

    • 我们的产品部署在不同的客户服务器上,以及很多的测试、联调、实验局、销售环境上。不同的客户和测试环境上都部署着不同版本的产品。当他们需要升级他们的产品到新的版本时,我们不仅需要让他们的管理员可以升级产品到新的版本,同时需要保留他们的已有数据。在升级产品的步骤中,我们清楚地知道客户数据库的当前版本,以及需要在该数据库上执行哪些数据库更新脚本,来更新数据库表结构与数据库中已存在的数据。当升级完成时,数据库表结构及数据应当与升级后的产品版本保持一致。

    • 当升级失败时(比如在升级过程中出现网络连接失败),我们应当支持对失败进行修复。

    更多Flyway文章(参考以下文档)

    二、Maven配置Flyway和jOOQ插件

    properties

    <!-- 数据库信息 -->
    <db.url>jdbc:mysql://127.0.0.1:33006/flyway_test?useUnicode=true&amp;characterEncoding=UTF-8</db.url>
    <db.username>root</db.username>
    <db.password>123456</db.password>

    plugins

    <!-- Flyway插件 -->
    <plugin>
        <groupId>org.flywaydb</groupId>
        <artifactId>flyway-maven-plugin</artifactId>
        <version>3.0</version>
        <!-- 在代码生成时候执行Flyway插件 -->
        <executions>
            <execution>
                <phase>generate-sources</phase>
                <goals>
                    <goal>migrate</goal>
                </goals>
            </execution>
        </executions>
        <!-- 指定Flyway迁移脚本文件目录 -->
        <configuration>
            <url>${db.url}</url>
            <user>${db.username}</user>
            <password>${db.password}</password>
            <locations>
                <location>filesystem:src/main/resources/db/migration</location>
            </locations>
        </configuration>
    </plugin>
    
    <!-- jOOQ代码生成插件 -->
    <plugin>
        <groupId>org.jooq</groupId>
        <artifactId>jooq-codegen-maven</artifactId>
        <version>${jooq.version}</version>
        <executions>
            <execution>
                <id>java-generator</id>
                <phase>generate-sources</phase>
                <goals>
                    <goal>generate</goal>
                </goals>
                <configuration>
                    <jdbc>
                        <url>${db.url}</url>
                        <user>${db.username}</user>
                        <password>${db.password}</password>
                    </jdbc>
                    <generator>
                        <database>
                            <name>org.jooq.util.mysql.MySQLDatabase</name>
                            <includes>.*</includes>
                            <inputSchema>flyway_test</inputSchema>
                        </database>
                        <target>
                            <packageName>test.generated</packageName>
                            <directory>target/generated-sources/jooq-mysql-java</directory>
                        </target>
                    </generator>
                </configuration>
            </execution>
        </executions>
    </plugin>

    三、数据库增量脚本

    假设已经插件MySQL数据库:flyway_test

    src/main/resources/db/migration目录(Flyway插件指定的location目录)下插件创建脚本文件:

    • V1__create_author.sql

    • V2__create_book.sql

    这三个脚本按照版本V[1,2,3...]创建,这是脚本的内容:

    # V1__create_author.sql
    CREATE TABLE `author` (
      `id` int NOT NULL,
      `first_name` varchar(255) DEFAULT NULL,
      `last_name` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`)
    );
    INSERT INTO author VALUES (1, 'George', 'Orwell');
    INSERT INTO author VALUES (2, 'Paulo', 'Coelho');
    # V2__create_book.sql
    CREATE TABLE `book` (
      `id` int NOT NULL,
      `author_id` int NOT NULL,
      `title` varchar(255) NOT NULL,
      PRIMARY KEY (`id`)
    );
    INSERT INTO book VALUES (1, 1, '1984');
    INSERT INTO book VALUES (2, 1, 'Animal Farm');
    INSERT INTO book VALUES (3, 2, 'O Alquimista');
    INSERT INTO book VALUES (4, 2, 'Brida');

    四、数据库迁移 & jOOQ代码生成

    执行Maven构建代码时候,上一步的V1/V2脚本Flyway会按照版本顺序去执行,并由jOOQ生成Java代码:

    mvn clean install

    成功后,新建测试用例测试:

    import org.jooq.DSLContext;
    import org.jooq.Record;
    import org.jooq.Result;
    import org.jooq.SQLDialect;
    import org.jooq.impl.DSL;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    
    import static test.generated.tables.Author.AUTHOR;
    
    /**
     * 测试类
     */
    public class Main {
        public static void main(String[] args) {
            // 用户名
            String userName = "root";
            // 密码
            String password = "123456";
            // mysql连接url
            String url = "jdbc:mysql://127.0.0.1:33006/flyway_test?useUnicode=true&characterEncoding=UTF-8";
    
            // Connection is the only JDBC resource that we need
            // PreparedStatement and ResultSet are handled by jOOQ, internally
            try (Connection conn = DriverManager.getConnection(url, userName, password)) {
                DSLContext create = DSL.using(conn, SQLDialect.MYSQL);
                Result<Record> result = create.select().from(AUTHOR).fetch();
    
                for (Record r : result) {
                    Integer id = r.getValue(AUTHOR.ID);
                    String firstName = r.getValue(AUTHOR.FIRST_NAME);
                    String lastName = r.getValue(AUTHOR.LAST_NAME);
    
                    /**
                     * 控制台输出
                     * ID: 1 first name: George last name: Orwell
                     * ID: 2 first name: Paulo last name: Coelho
                     */
                    System.out.println("ID: " + id + " first name: " + firstName + " last name: " + lastName);
                }
    
                // 关闭连接对象
                conn.close();
            }
            // For the sake of this tutorial, let's keep exception handling simple
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    五、数据库变动

    近期书库里多了中文书籍,需要为book表添加语言种类字段

    src/main/resources/db/migration目录下新增修改数据库脚本:

    # V3__book_add_language.sql
    ALTER TABLE `book` ADD COLUMN `language_id` int(7) DEFAULT '1' NOT NULL;

    重新运行Maven构建:

    mvn clean install

    测试用例:

    import org.jooq.DSLContext;
    import org.jooq.Record;
    import org.jooq.Result;
    import org.jooq.SQLDialect;
    import org.jooq.impl.DSL;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    
    import static test.generated.tables.Author.AUTHOR;
    import static test.generated.tables.Book.BOOK;
    
    /**
     * 测试类
     */
    public class BookMain {
        public static void main(String[] args) {
            // 用户名
            String userName = "root";
            // 密码
            String password = "123456";
            // mysql连接url
            String url = "jdbc:mysql://127.0.0.1:33006/flyway_test?useUnicode=true&characterEncoding=UTF-8";
    
            // Connection is the only JDBC resource that we need
            // PreparedStatement and ResultSet are handled by jOOQ, internally
            try (Connection conn = DriverManager.getConnection(url, userName, password)) {
                DSLContext create = DSL.using(conn, SQLDialect.MYSQL);
                Result<Record> result = create.select().from(BOOK).fetch();
    
                for (Record r : result) {
                    Integer id = r.getValue(BOOK.ID);
                    String firstName = r.getValue(BOOK.TITLE);
                    Integer languageId = r.getValue(BOOK.LANGUAGE_ID);
    
                    /**
                     * 控制台输出
                     * ID: 1 title: 1984 language: 英文
                     * ID: 2 title: Animal Farm language: 英文
                     * ID: 3 title: O Alquimista language: 英文
                     * ID: 4 title: Brida language: 英文
                     */
                    System.out.println("ID: " + id + " title: "
                            + firstName + " language: " + (languageId.intValue() == 1 ? "英文" : "中文"));
                }
    
                // 关闭连接对象
                conn.close();
            }
            // For the sake of this tutorial, let's keep exception handling simple
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    【jOOQ中文】教程代码都会放在码云,希望多多宣传给Star(^_−)☆。

  • 相关阅读:
    使用参数化SQL语句进行模糊查找(转载)
    ASP.NET 数据绑定控件(转)
    C#把datetime类型的日期转化成其他格式方法总结
    asp.net MVC中form提交和控制器接受form提交过来的数据(转)
    图说世界编程语言排行
    Android笔记——Matrix
    设计模式——代理模式
    Android笔记——Handler Runnable与Thread的区别
    Android笔记——AsyncTask介绍
    Eclipse---java项目导入报错更改
  • 原文地址:https://www.cnblogs.com/xiang--liu/p/9710270.html
Copyright © 2011-2022 走看看