Flyway和jOOQ带来无与伦比的SQL开发生产力

flyway-logo-transparent-300
在执行数据库迁移时,我们的Data Geekery建议将jOOQFlyway结合使用-轻松实现数据库迁移 。 在本文中,我们将研究一种简单的方法来开始使用这两个框架。

哲学

在各种开发设置中,jOOQ和Flyway可以通过多种方式相互交互。 在本教程中,我们将仅展示这种框架团队的一种变体-对于大多数用例来说,这种变体特别引人注目。

以下方法背后的一般原理和工作流程可总结为:

  • 1.数据库增量
  • 2.数据库迁移
  • 3.代码重新生成
  • 4.发展

每当您需要修改数据库中的某些内容时,可以一次又一次地重复上述四个步骤。 更具体地说,让我们考虑:

  • 1.数据库增量数据库中需要一个新列,因此您需要在Flyway脚本中编写必要的DDL
  • 2.数据库迁移 –该Flyway脚本现在已成为可交付成果的一部分,您可以与所有可以使用其迁移数据库的开发人员共享,下次他们检查您的更改时
  • 3.代码重新生成 –迁移数据库后,您将在本地重新生成所有jOOQ工件(请参阅代码生成 )。
  • 4.开发 –您将继续开发业务逻辑,针对经过修改的生成的数据库模式编写代码

Maven项目配置–属性

在我们的pom.xml中定义了以下属性,以便能够在插件配置之间重用它们:

<properties>
    <db.url>jdbc:h2:~/flyway-test</db.url>
    <db.username>sa</db.username>
</properties>

Maven项目配置–依赖关系

尽管可以在独立的迁移脚本中使用jOOQ和Flyway,但在本教程中,我们将使用Maven进行标准项目设置。 您还将在GitHub找到本教程的源代码,并在此处 找到完整的pom.xml文件

这些是我们在Maven配置中使用的依赖项:

<!-- We'll add the latest version of jOOQ 
     and our JDBC driver - in this case H2 -->
<dependency>
    <groupId>org.jooq</groupId>
    <artifactId>jooq</artifactId>
    <version>3.4.0</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.177</version>
</dependency>

<!-- For improved logging, we'll be using 
     log4j via slf4j to see what's going
     on during migration and code generation -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.16</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.5</version>
</dependency>

<!-- To esnure our code is working, we're
     using JUnit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>

Maven项目配置–插件

在依赖关系之后,让我们简单地像这样添加Flyway和jOOQ Maven插件。 Flyway插件:

<plugin>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-maven-plugin</artifactId>
    <version>3.0</version>

    <!-- Note that we're executing the Flyway
         plugin in the "generate-sources" phase -->
    <executions>
        <execution>
            <phase>generate-sources</phase>
            <goals>
                <goal>migrate</goal>
            </goals>
        </execution>
    </executions>

    <!-- Note that we need to prefix the db/migration
         path with filesystem: to prevent Flyway
         from looking for our migration scripts
         only on the classpath -->
    <configuration>
        <url>${db.url}</url>
        <user>${db.username}</user>
        <locations>
            <location>filesystem:src/main/resources/db/migration</location>
        </locations>
    </configuration>
</plugin>

上面的Flyway Maven插件配置将在编译Java源代码之前从src/main/resources/db/migration读取并执行所有数据库迁移脚本。 尽管Flyway 官方文档建议在compile阶段进行迁移,但是jOOQ代码生成器依赖于代码生成之前完成的此类迁移。

在Flyway插件之后,我们将添加jOOQ Maven插件。 有关更多详细信息,请参阅手册中有关代码生成配置的部分

<plugin>
    <groupId>org.jooq</groupId>
    <artifactId>jooq-codegen-maven</artifactId>
    <version>${org.jooq.version}</version>

    <!-- The jOOQ code generation plugin is also 
         executed in the generate-sources phase,
         prior to compilation -->
    <executions>
        <execution>
            <phase>generate-sources</phase>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>

    <!-- This is a minimal working configuration. 
         See the manual's section about the code
         generator for more details -->
    <configuration>
        <jdbc>
            <url>${db.url}</url>
            <user>${db.username}</user>
        </jdbc>
        <generator>
            <database>
                <includes>.*</includes>
                <inputSchema>FLYWAY_TEST</inputSchema>
            </database>
            <target>
                <packageName>org.jooq.example.flyway.db.h2</packageName>
                <directory>target/generated-sources/jooq-h2</directory>
            </target>
        </generator>
    </configuration>
</plugin>

现在,此配置将读取FLYWAY_TEST模式,并将其反向工程到target/generated-sources/jooq-h2目录中,并在其中进入org.jooq.example.flyway.db.h2包。

1.数据库增量

现在,当我们开始开发数据库时。 为此,我们将创建数据库增量脚本,并将其放入src/main/resources/db/migration目录中,如先前为Flyway插件配置的那样。 我们将添加以下文件:

  • V1__initialise_database.sql
  • V2__create_author_table.sql
  • V3__create_book_table_and_records.sql

这三个脚本为我们的架构版本1-3(请注意大写的V!)建模。 这是脚本的内容

-- V1__initialise_database.sql
DROP SCHEMA flyway_test IF EXISTS;

CREATE SCHEMA flyway_test;
-- V2__create_author_table.sql
CREATE SEQUENCE flyway_test.s_author_id START WITH 1;

CREATE TABLE flyway_test.author (
  id INT NOT NULL,
  first_name VARCHAR(50),
  last_name VARCHAR(50) NOT NULL,
  date_of_birth DATE,
  year_of_birth INT,
  address VARCHAR(50),

  CONSTRAINT pk_t_author PRIMARY KEY (ID)
);
-- V3__create_book_table_and_records.sql
CREATE TABLE flyway_test.book (
  id INT NOT NULL,
  author_id INT NOT NULL,
  title VARCHAR(400) NOT NULL,

  CONSTRAINT pk_t_book PRIMARY KEY (id),
  CONSTRAINT fk_t_book_author_id FOREIGN KEY (author_id) REFERENCES flyway_test.author(id)
);


INSERT INTO flyway_test.author VALUES (next value for flyway_test.s_author_id, 'George', 'Orwell', '1903-06-25', 1903, null);
INSERT INTO flyway_test.author VALUES (next value for flyway_test.s_author_id, 'Paulo', 'Coelho', '1947-08-24', 1947, null);

INSERT INTO flyway_test.book VALUES (1, 1, '1984');
INSERT INTO flyway_test.book VALUES (2, 1, 'Animal Farm');
INSERT INTO flyway_test.book VALUES (3, 2, 'O Alquimista');
INSERT INTO flyway_test.book VALUES (4, 2, 'Brida');

2.数据库迁移和3.代码重新生成

以上三个脚本由Flyway拾取,并按版本顺序执行。 这可以通过执行以下命令非常简单地看到:

mvn clean install

然后观察Flyway的日志输出...

[INFO] --- flyway-maven-plugin:3.0:migrate (default) @ jooq-flyway-example ---
[INFO] Database: jdbc:h2:~/flyway-test (H2 1.4)
[INFO] Validated 3 migrations (execution time 00:00.004s)
[INFO] Creating Metadata table: "PUBLIC"."schema_version"
[INFO] Current version of schema "PUBLIC": <>
[INFO] Migrating schema "PUBLIC" to version 1
[INFO] Migrating schema "PUBLIC" to version 2
[INFO] Migrating schema "PUBLIC" to version 3
[INFO] Successfully applied 3 migrations to schema "PUBLIC" (execution time 00:00.073s).

…以及从控制台上的jOOQ:

[INFO] --- jooq-codegen-maven:3.5.0-SNAPSHOT:generate (default) @ jooq-flyway-example ---
[INFO] Using this configuration:
...
[INFO] Generating schemata      : Total: 1
[INFO] Generating schema        : FlywayTest.java
[INFO] ----------------------------------------------------------
[....]
[INFO] GENERATION FINISHED!     : Total: 337.576ms, +4.299ms

4.发展

请注意,每次有人将新的迁移脚本添加到Maven模块时,上述所有步骤都会自动执行。 例如,一个团队成员可能已经提交了一个新的迁移脚本,您可以将其检出,重建并为您自己的开发或集成测试数据库获取jOOQ生成的最新资源。

现在,这些步骤已完成,您可以继续编写数据库查询。 想象以下测试案例

import org.jooq.Result;
import org.jooq.impl.DSL;
import org.junit.Test;

import java.sql.DriverManager;

import static java.util.Arrays.asList;
import static org.jooq.example.flyway.db.h2.Tables.*;
import static org.junit.Assert.assertEquals;

public class AfterMigrationTest {

    @Test
    public void testQueryingAfterMigration() throws Exception {
        try (Connection c = DriverManager.getConnection("jdbc:h2:~/flyway-test", "sa", "")) {
            Result<?> result =
            DSL.using(c)
               .select(
                   AUTHOR.FIRST_NAME,
                   AUTHOR.LAST_NAME,
                   BOOK.ID,
                   BOOK.TITLE
               )
               .from(AUTHOR)
               .join(BOOK)
               .on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
               .orderBy(BOOK.ID.asc())
               .fetch();

            assertEquals(4, result.size());
            assertEquals(asList(1, 2, 3, 4), result.getValues(BOOK.ID));
        }
    }
}

如果再次运行mvn clean install ,上述集成测试现在将编译并通过!

重申

一旦您开始以这种方式执行数据库修改,这种方法的力量就会变得清晰。 假设我们团队中的法国人更喜欢以自己的方式做事(无意冒犯):

-- V4__le_french.sql
ALTER TABLE flyway_test.book 
  ALTER COLUMN title RENAME TO le_titre;

他们签入,您签出新的数据库迁移脚本,运行

mvn clean install

然后观察日志输出:

[INFO] --- flyway-maven-plugin:3.0:migrate (default) @ jooq-flyway-example ---
[INFO] --- flyway-maven-plugin:3.0:migrate (default) @ jooq-flyway-example ---
[INFO] Database: jdbc:h2:~/flyway-test (H2 1.4)
[INFO] Validated 4 migrations (execution time 00:00.005s)
[INFO] Current version of schema "PUBLIC": 3
[INFO] Migrating schema "PUBLIC" to version 4
[INFO] Successfully applied 1 migration to schema "PUBLIC" (execution time 00:00.016s).

到目前为止一切顺利,但随后:

[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] C:\...\AfterMigrationTest.java:[24,19] error: cannot find symbol
[INFO] 1 error

回到Java集成测试时,我们可以立即看到TITLE列仍在被引用,但不再存在:

public class AfterMigrationTest {

    @Test
    public void testQueryingAfterMigration() throws Exception {
        try (Connection c = DriverManager.getConnection("jdbc:h2:~/flyway-test", "sa", "")) {
            Result<?> result =
            DSL.using(c)
               .select(
                   AUTHOR.FIRST_NAME,
                   AUTHOR.LAST_NAME,
                   BOOK.ID,
                   BOOK.TITLE
                   //   ^^^^^ This column no longer exists. 
                   //   We'll have to rename it to LE_TITRE
               )
               .from(AUTHOR)
               .join(BOOK)
               .on(AUTHOR.ID.eq(BOOK.AUTHOR_ID))
               .orderBy(BOOK.ID.asc())
               .fetch();

            assertEquals(4, result.size());
            assertEquals(asList(1, 2, 3, 4), result.getValues(BOOK.ID));
        }
    }
}

结论

本教程非常轻松地展示了如何使用Flyway和jOOQ构建坚如磐石的开发流程,以在开发生命周期的早期(即在编译时而不是在生产时)防止与SQL有关的错误!

jooq在Java中写SQL的最佳方法

翻译自: https://www.javacodegeeks.com/2014/06/flyway-and-jooq-for-unbeatable-sql-development-productivity.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值