
  При выполнении миграции баз данных мы в Data Geekery рекомендуем использовать jOOQ с Flyway — Миграция баз данных Made Easy .  В этом посте мы рассмотрим простой способ начать работу с двумя фреймворками. 
философия
Существует множество способов взаимодействия jOOQ и Flyway друг с другом в различных настройках разработки. В этом уроке мы покажем только один вариант такой командной игры фреймворка — вариант, который мы находим особенно привлекательным для большинства случаев использования.
Общая философия и рабочий процесс, лежащий в основе следующего подхода, могут быть обобщены следующим образом:
- 1. Приращение базы данных
- 2. Миграция базы данных
- 3. Повторная генерация кода
- 4. Разработка
Четыре вышеуказанных шага можно повторять снова и снова, каждый раз, когда вам нужно что-то изменить в вашей базе данных. Конкретнее, давайте рассмотрим:
- 1. Приращение базы данных — вам нужен новый столбец в вашей базе данных, поэтому вы пишете необходимый DDL в скрипте Flyway
- 2. Перенос базы данных. Этот сценарий Flyway теперь является частью вашего конечного результата, которым вы можете поделиться со всеми разработчиками, которые могут перенести свои базы данных вместе с ним, при следующей проверке ваших изменений
- 3. Повторная генерация кода — после переноса базы данных вы регенерируете все артефакты jOOQ (см. Генерацию кода ) локально
- 4. Разработка. Вы продолжаете разрабатывать свою бизнес-логику, писать код для обновленной схемы базы данных.
0,1. Конфигурация проекта Maven — Свойства
Следующие свойства определены в нашем pom.xml, чтобы можно было повторно использовать их между конфигурациями плагинов:
| 1 2 3 4 | <properties>    <db.url>jdbc:h2:~/flyway-test</db.url>    <db.username>sa</db.username></properties> | 
0.2. Конфигурация проекта Maven — Зависимости
Хотя jOOQ и Flyway можно использовать в автономных сценариях миграции, в этом руководстве мы будем использовать Maven для стандартной настройки проекта. Вы также найдете исходный код этого руководства на GitHub и полный файл pom.xml здесь .
Это зависимости, которые мы используем в нашей конфигурации Maven:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <!-- 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> | 
0,3. Конфигурация проекта Maven — Плагины
После зависимостей давайте просто добавим плагины Flyway и jOOQ Maven следующим образом. Плагин Flyway:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <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 будет считывать и выполнять все сценарии миграции базы данных из src/main/resources/db/migration до компиляции исходного кода Java.  В то время как официальная документация по Flyway предполагает, что миграции должны выполняться на этапе compile , генератор кода jOOQ полагается на то, что такие миграции выполнялись до генерации кода. 
После плагина Flyway мы добавим плагин jOOQ Maven. Для более подробной информации, пожалуйста, обратитесь к разделу руководства о конфигурации генерации кода .
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <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 и FLYWAY_TEST в 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!). Вот содержимое скриптов
| 1 2 3 4 | -- V1__initialise_database.sqlDROP SCHEMA flyway_test IF EXISTS;CREATE SCHEMA flyway_test; | 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 | -- V2__create_author_table.sqlCREATESEQUENCEflyway_test.s_author_id START WITH1;CREATETABLEflyway_test.author (  id INTNOTNULL,  first_name VARCHAR(50),  last_name VARCHAR(50) NOTNULL,  date_of_birth DATE,  year_of_birth INT,  address VARCHAR(50),  CONSTRAINTpk_t_author PRIMARYKEY(ID)); | 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | -- V3__create_book_table_and_records.sqlCREATETABLEflyway_test.book (  id INTNOTNULL,  author_id INTNOTNULL,  title VARCHAR(400) NOTNULL,  CONSTRAINTpk_t_book PRIMARYKEY(id),  CONSTRAINTfk_t_book_author_id FOREIGNKEY(author_id) REFERENCESflyway_test.author(id));INSERTINTOflyway_test.author VALUES(nextvalue forflyway_test.s_author_id, 'George', 'Orwell', '1903-06-25', 1903, null);INSERTINTOflyway_test.author VALUES(nextvalue forflyway_test.s_author_id, 'Paulo', 'Coelho', '1947-08-24', 1947, null);INSERTINTOflyway_test.book VALUES(1, 1, '1984');INSERTINTOflyway_test.book VALUES(2, 1, 'Animal Farm');INSERTINTOflyway_test.book VALUES(3, 2, 'O Alquimista');INSERTINTOflyway_test.book VALUES(4, 2, 'Brida'); | 
2. Миграция базы данных и 3. Восстановление кода
Три вышеупомянутых скрипта подобраны Flyway и выполнены в порядке версий. Это можно увидеть очень просто, выполнив:
| 1 | mvn clean install | 
А затем, наблюдая за выходом журнала из Flyway…
| 1 2 3 4 5 6 7 8 9 | [INFO] --- flyway-maven-plugin:3.0:migrate (default) @ jooq-flyway-example ---[INFO] Database: jdbc:h2:~/flyway-test (H2 1.4)[INFO] Validated 3migrations (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 3migrations to schema "PUBLIC"(execution time 00:00.073s). | 
… и из jOOQ на консоли:
| 1 2 3 4 5 6 7 8 | [INFO] --- jooq-codegen-maven:3.5.0-SNAPSHOT:generate (default) @ jooq-flyway-example ---[INFO] Using thisconfiguration:...[INFO] Generating schemata      : Total: 1[INFO] Generating schema        : FlywayTest.java[INFO] ----------------------------------------------------------[....][INFO] GENERATION FINISHED!     : Total: 337.576ms, +4.299ms | 
4. Разработка
Обратите внимание, что все предыдущие шаги выполняются автоматически, каждый раз, когда кто-то добавляет новые скрипты миграции в модуль Maven. Например, участник команды мог зафиксировать новый сценарий миграции, проверить его, перестроить и получить последние сгенерированные jOOQ источники для своей собственной базы данных разработки или тестирования интеграции.
Теперь, когда эти шаги выполнены, вы можете приступить к написанию запросов к базе данных. Представьте себе следующий тест
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | importorg.jooq.Result;importorg.jooq.impl.DSL;importorg.junit.Test;importjava.sql.DriverManager;importstaticjava.util.Arrays.asList;importstaticorg.jooq.example.flyway.db.h2.Tables.*;importstaticorg.junit.Assert.assertEquals;publicclassAfterMigrationTest {    @Test    publicvoidtestQueryingAfterMigration() throwsException {        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 , вышеприведенный тест интеграции будет скомпилирован и пройден! 
Подтверждают
Сила этого подхода становится очевидной, как только вы начнете выполнять модификации базы данных таким способом Давайте предположим, что французский парень в нашей команде предпочитает, чтобы все было по-своему (без обид)
| 1 2 3 | -- V4__le_french.sqlALTERTABLEflyway_test.book   ALTERCOLUMNtitle RENAME TOle_titre; | 
Они проверяют это, вы проверяете новый скрипт миграции базы данных, запускаете
| 1 | mvn clean install | 
А затем просмотрите вывод журнала:
| 1 2 3 4 5 6 7 | [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 4migrations (execution time 00:00.005s)[INFO] Current version of schema "PUBLIC": 3[INFO] Migrating schema "PUBLIC"to version 4[INFO] Successfully applied 1migration to schema "PUBLIC"(execution time 00:00.016s). | 
Пока все хорошо, но позже:
| 1 2 3 4 | [ERROR] COMPILATION ERROR :[INFO] -------------------------------------------------------------[ERROR] C:\...\AfterMigrationTest.java:[24,19] error: cannot find symbol[INFO] 1error | 
Когда мы вернемся к нашему тесту интеграции Java, мы сразу увидим, что на столбец TITLE все еще ссылаются, но он больше не существует:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | publicclassAfterMigrationTest {    @Test    publicvoidtestQueryingAfterMigration() throwsException {        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, на самых ранних этапах жизненного цикла разработки — сразу во время компиляции, а не в процессе производства!
| Ссылка: | Flyway и jOOQ для непревзойденной производительности SQL от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и AND JOOQ . | 
