javascript
flyway spring_关于使用Flyway在Spring Boot中管理数据更改的建议
flyway spring
介紹 (Introduction)
Database migrations are essential for the development of an application to progress and scale in any meaningful way.
數(shù)據(jù)庫遷移對于應(yīng)用程序的開發(fā)以任何有意義的方式進(jìn)行和擴(kuò)展至關(guān)重要。
Among other things, migrations keep changes to the database recorded in version control, automated, stateful 1, and, perhaps most importantly, reproducible.
除此之外,移民最重要的, 可重復(fù)的不斷變化記錄在版本控制數(shù)據(jù)庫, 自動化,狀態(tài) 1,或許。
[1]: I’m not sure if stateful is a common term for this. For me, migrations being stateful means that looking at any database, you can tell what ‘state’ the database is in; that is, what migrations have been applied to it so far. Flyway accomplishes this by creating a history table to record all attempted migrations.
[1]:我不確定有狀態(tài)是否是通用術(shù)語。 對我來說,遷移是有狀態(tài)的,意味著查看任何數(shù)據(jù)庫,您就可以知道數(shù)據(jù)庫所在的“狀態(tài)”。 也就是說,到目前為止已對其應(yīng)用了哪些遷移。 Flyway通過創(chuàng)建一個歷史記錄表來記錄所有嘗試的遷移來實(shí)現(xiàn)此目的。
問題 (The Issue)
Photo by Arthur Yeti on Unsplash照片由Arthur Yeti在Unsplash上拍攝While schema changes are “respected” enough by developers to be put into migrations, data changes are often not that lucky; data changes are more likely to be performed on an ad-hoc basis on individual environments.
盡管開發(fā)人員足夠尊重架構(gòu)更改以進(jìn)行遷移,但數(shù)據(jù)更改通常并不那么幸運(yùn)。 數(shù)據(jù)更改更有可能在個別環(huán)境中臨時執(zhí)行。
The downsides of such an approach are, in essence, the opposite of the migration approach’s benefits; these data changes are [often] not committed to version control, not part of the automated deployment pipeline, stateless 2, and hard to track and reproduce.
從本質(zhì)上講,這種方法的缺點(diǎn)與遷移方法的好處相反。 這些數(shù)據(jù)更改[通常]不致力于版本控制,不屬于自動部署管道的一部分,是無狀態(tài)的,并且難以跟蹤和再現(xiàn)。
These disadvantages are especially apparent when such data changes pertain to what’s often referred to as master data; that is, records that the application assumes, depends on, and might not have a graceful way of dealing with their absence. Such data may include user types (user, admin, etc…), content categories, or localization-related records, to name some.
當(dāng)此類數(shù)據(jù)更改與通常稱為主數(shù)據(jù)的內(nèi)容有關(guān)時,這些缺點(diǎn)尤為明顯。 也就是說,應(yīng)用程序假定的記錄,依賴的記錄以及可能沒有適當(dāng)?shù)姆椒▉硖幚硭鼈兊娜笔А?這些數(shù)據(jù)可能包括用戶類型(用戶,管理員等),內(nèi)容類別或與本地化相關(guān)的記錄,僅舉幾例。
Data changes are as essential to the end result as the application code or schema changes and, thus, should be treated equally.
數(shù)據(jù)更改對于最終結(jié)果至關(guān)重要,就像應(yīng)用程序代碼或架構(gòu)更改一樣,因此應(yīng)同等對待。
[2]: In the sense that looking at the history table of migrations, there’s no way to tell if certain data changes were applied.
[2]:從查看遷移的歷史記錄表的意義上講,無法確定是否應(yīng)用了某些數(shù)據(jù)更改。
我們能做什么 (What We Can Do)
A quick workaround could be to commit any data changes done through SQL to a dedicated location in the codebase and apply them manually.
一種快速的解決方法是將通過SQL完成的所有數(shù)據(jù)更改提交到代碼庫中的專用位置,然后手動應(yīng)用它們。
While this is not precisely stateful or automatically reproducible, it does help to get such changes into version control and might make tracking and reproducing them a bit more manageable.
盡管這不是精確的有狀態(tài)或自動可復(fù)制的,但確實(shí)有助于將此類更改納入版本控制,并且可能使跟蹤和復(fù)制它們變得更易于管理。
But can we do better?
但是,我們可以做得更好嗎?
建議 (The Suggestion)
A cleaner approach would be to treat data changes similar to schema changes; as first-class database migrations. After all, data changes are as essential to the end result as the application code or schema changes and, thus, should be treated equally.
較干凈的方法是將數(shù)據(jù)更改與架構(gòu)更改類似地對待。 作為一流的數(shù)據(jù)庫遷移。 畢竟,數(shù)據(jù)更改對于最終結(jié)果至關(guān)重要,就像應(yīng)用程序代碼或架構(gòu)更改一樣,因此應(yīng)同等對待。
In the context of Flyway, this translates into putting data changes in SQL files alongside other migrations, either versioned or repeatable.
在Flyway的上下文中,這意味著將數(shù)據(jù)更改與其他遷移( 版本化或可重復(fù)的)一起放入SQL文件中。
Photo by William Rouse on Unsplash 威廉·羅斯 ( William Rouse)在Unsplash上拍攝Flyway遷移速成課程 (A Crash Course on Flyway Migrations)
In Flyway, a versioned migration is one that 1- starts with a V, 2- gets applied once, and 3- cannot be modified after it’s been applied. This type is the most common and is often used for schema migrations.
在Flyway中, 版本化遷移是這樣的遷移:1從V開始,2被應(yīng)用一次,3被應(yīng)用后不能修改。 此類型是最常見的類型,通常用于架構(gòu)遷移。
A repeatable migration, on the other hand, is one that 1- starts with an R, 2- may be applied multiple times, and 3- can be modified after it’s been applied. This type is less know and is suggested for creating views, procedures, functions, etc.
另一方面, 可重復(fù)的遷移是這樣的遷移:1以R開頭,2可以被多次應(yīng)用,3可以在應(yīng)用后被修改。 這種類型鮮為人知,建議用于創(chuàng)建視圖,過程,函數(shù)等。
The challenge with repeatable migrations is writing the SQL code. Code in such migrations should be safe to rerun multiple times without producing unintended side effects such as erroring or duplicating records.
可重復(fù)遷移的挑戰(zhàn)在于編寫SQL代碼。 這樣的遷移中的代碼應(yīng)可以安全地重新運(yùn)行多次,而不會產(chǎn)生意外的副作用,例如錯誤記錄或重復(fù)記錄。
共享數(shù)據(jù)遷移的選擇 (The Choice for Shared Data Migrations)
For shared data migrations across all environments, the choice is largely practical and personal.
對于跨所有環(huán)境的共享數(shù)據(jù)遷移,選擇主要是實(shí)際和個人的。
Writing versioned migrations means that your master data is potentially going to be split across multiple files with schema migration files in between. It does free you from having to write repeatable code, though.
編寫版本化的遷移意味著您的主數(shù)據(jù)可能會被拆分成多個文件,而架構(gòu)遷移文件將介于兩個文件之間。 但是,它使您不必編寫可重復(fù)的代碼。
On the other hand, writing repeatable migrations means that your master data can all sit in one file or a number of data files. It also means that data changes stay out of the way of, and are quite distinguishable from, schema changes. However, it does require you to write repeatable code (which for insert statements is quite manageable as we’ll see later for MySQL at least).
另一方面,編寫可重復(fù)的遷移意味著您的主數(shù)據(jù)可以全部放在一個文件或多個數(shù)據(jù)文件中。 這也意味著數(shù)據(jù)更改不影響模式更改,并且與模式更改完全不同。 但是,它確實(shí)需要您編寫可重復(fù)的代碼(對于插入語句,這是相當(dāng)可管理的,至少我們稍后將在MySQL上看到)。
針對特定環(huán)境的數(shù)據(jù)遷移的選擇 (The Choice for Environment-specific Data Migrations)
For data migrations that should only be applied to a specific environment (think test data for a test environment or dummy login credentials for dev), the same tradeoffs between versioned and repeatable migrations apply. However, versioned migrations have one more disadvantage in this case; environments other than the one receiving the versioned migration will seem to have “skipped” some versions.
對于僅應(yīng)應(yīng)用于特定環(huán)境的數(shù)據(jù)遷移(對于測試環(huán)境考慮測試數(shù)據(jù),對于開發(fā)人員則考慮虛擬登錄憑據(jù)),在版本化遷移和可重復(fù)遷移之間應(yīng)用相同的權(quán)衡。 但是,在這種情況下,版本化遷移還有另一個缺點(diǎn)。 除了接受版本化遷移的環(huán)境以外,其他環(huán)境似乎已經(jīng)“跳過”了某些版本。
Photo on foter.com foter.com上的照片我的建議 (My Suggestion)
If I haven’t already given it away, I prefer repeatable migrations for all data changes to keep them visibly different, maintain continuous versioning for schema changes across all environments, and keep things consistent for both shared and environment-specific data migrations.
如果我還沒有放棄的話,我希望對所有數(shù)據(jù)更改進(jìn)行可重復(fù)的遷移,以使它們在視覺上保持不同,為所有環(huán)境中的架構(gòu)更改保持連續(xù)的版本控制,并使共享數(shù)據(jù)和特定于環(huán)境的數(shù)據(jù)遷移保持一致。
細(xì)節(jié) (The Details)
The specifics of how to, exactly, accomplish this suggestion for three environments; dev, staging, and prod in Spring Boot 2.x can be summarized as:
如何針對三種環(huán)境準(zhǔn)確實(shí)現(xiàn)此建議的細(xì)節(jié); Spring Boot 2.x中的 dev , staging和prod可以總結(jié)為:
1- Create the following properties files:* application.properties* application-non-prod.properties* application-dev.properties* application-staging.properties* application-prod.properties
1-創(chuàng)建以下屬性文件: * application.properties * application-non-prod.properties * application-dev.properties * application-staging.properties * application-prod.properties
2- Create the following directories at the classpath. In Spring Boot as you’re probably aware, anything under /src/main/resources is added to the classpath:* db/migration/shared* db/migration/non-prod* db/migration/dev* db/migration/staging* db/migration/prod
2-在類路徑下創(chuàng)建以下目錄 。 如您所知,在Spring Boot中, /src/main/resources都添加到類路徑中: * db / migration / shared * db / migration / non-prod * db / migration / dev * db / migration / staging * db /遷移/產(chǎn)品
3- In the properties file for each environment, override the spring.flyway.locations property, which accepts a comma-separated list of locations. In Spring Boot, the default location is db/migration.
3-在每個環(huán)境的屬性文件中,覆蓋spring.flyway.locations屬性,該屬性接受以逗號分隔的位置列表。 在Spring Boot中,默認(rèn)位置是db/migration 。
We want to modify the migrations locations in such a way that:dev reads migrations from the shared, non-prod, and dev directories.staging reads migrations from the shared, non-prod, and staging directories.prod reads migrations from the shared, and prod directories only.
我們希望以以下方式修改遷移位置: dev從shared , non-prod和dev目錄中讀取遷移。 staging從shared , non-prod和暫存目錄讀取遷移。 prod僅從shared和prod目錄讀取遷移。
This can be accomplished by setting the locations property as follows:
可以通過如下設(shè)置locations屬性來實(shí)現(xiàn):
* In application-dev.properties, set:
*在application-dev.properties ,設(shè)置:
spring.flyway.locations=classpath:/db/migration/shared,classpath:/db/migration/non-prod,classpath:/db/migration/dev* In application-staging.properties , set:
*在application-staging.properties ,設(shè)置:
spring.flyway.locations=classpath:/db/migration/shared,classpath:/db/migration/non-prod,classpath:/db/migration/staging* In application-prod.properties , set:
*在application-prod.properties ,設(shè)置:
spring.flyway.locations=classpath:/db/migration/shared,classpath:/db/migration/prod4- For any database change, follow these conventions:* Is it a schema change? Create a versioned migration in the shared directory.* Is it a master data change? Create a repeatable migration or update an existing one in the shared directory.* Is it a data change that shouldn’t make its way to production but is ok on other environments? Create a repeatable migration or update an existing one in the non-prod directory.* Is it a data change specific to the dev, staging, or prod environment? Create a repeatable migration or update an existing one in the dev, staging, or prod directory, respectively.
4-對于任何數(shù)據(jù)庫更改,請遵循以下約定:*是架構(gòu)更改嗎? 在共享目錄中創(chuàng)建版本化的遷移。*是主數(shù)據(jù)更改嗎? 創(chuàng)建可重復(fù)的遷移或更新共享目錄中的現(xiàn)有遷移。*這是不應(yīng)該用于生產(chǎn)但在其他環(huán)境中還可以的數(shù)據(jù)更改嗎? 創(chuàng)建可重復(fù)的遷移或更新非生產(chǎn)目錄中的現(xiàn)有遷移。*這是特定于dev , staging或prod環(huán)境的數(shù)據(jù)更改嗎? 在dev , staging或prod目錄中分別創(chuàng)建可重復(fù)的遷移或更新現(xiàn)有的遷移。
Photo on foter.com foter.com上的照片一個示例實(shí)現(xiàn) (An Example Implementation)
To create a minimal application to test this setup, we can start with an empty Spring Boot project with at least the following dependencies; spring-boot-starter-web, spring-boot-starter-data-jpa, flyway-core, and mysql-connector-java and walk through the following steps 3:
為了創(chuàng)建一個最小的應(yīng)用程序來測試該設(shè)置,我們可以從一個空的Spring Boot項(xiàng)目開始,該項(xiàng)目至少具有以下依賴性: spring-boot-starter-web , spring-boot-starter-data-jpa , flyway-core和mysql-connector-java并完成以下步驟3:
1- Make sure you have a MySQL server running locally on the default port 3306 with a username of root and no password or change values across this tutorial according to your individual setup.
1-確保您的MySQL服務(wù)器在默認(rèn)端口3306上本地運(yùn)行,用戶名root ,沒有密碼,或者根據(jù)您的個人設(shè)置在本教程中更改值。
1.1- Access the MySQL server:
1.1-訪問MySQL服務(wù)器:
mysql -u root1.2- Then create the dev, staging, and prod databases with:
1.2-然后使用以下命令創(chuàng)建dev , staging和prod數(shù)據(jù)庫:
CREATE DATABASE managing_flyway_migrations_dev;CREATE DATABASE managing_flyway_migrations_staging;
CREATE DATABASE managing_flyway_migrations_prod;
2- Create properties files under /src/main/resources.2.1- Create a file called application.properties with the following content:
2-在/src/main/resources下創(chuàng)建屬性文件.2.1-創(chuàng)建一個名為application.properties的文件,其內(nèi)容如下:
spring.jpa.open-in-view=false# Change this value to 1.2 for the Third Run or remove all togetherspring.flyway.target=1.1
2.2- Create an empty file called application-non-prod.properties .3
2.2-創(chuàng)建一個名為application-non-prod.properties的空文件。
2.3- Create a file called application-dev.properties with the following content:
2.3-創(chuàng)建一個名為application-dev.properties的文件,其內(nèi)容如下:
spring.profiles.include=non-prodserver.port=8081spring.datasource.url=jdbc:mysql://localhost:3306spring.datasource.username=root
spring.datasource.password=
spring.datasource.name=managing_flyway_migrations_devspring.flyway.locations=classpath:/db/migration/shared,classpath:/db/migration/non-prod,classpath:/db/migration/dev
spring.flyway.schemas=${spring.datasource.name}
2.4- Create a file called application-staging.properties with the following content:
2.4-創(chuàng)建一個名為application-staging.properties的文件,其內(nèi)容如下:
spring.profiles.include=non-prodserver.port=8082spring.datasource.url=jdbc:mysql://localhost:3306spring.datasource.username=root
spring.datasource.password=
spring.datasource.name=managing_flyway_migrations_stagingspring.flyway.locations=classpath:/db/migration/shared,classpath:/db/migration/non-prod,classpath:/db/migration/staging
spring.flyway.schemas=${spring.datasource.name}
2.5- Create a file called application-prod.properties with the following content:
2.5-創(chuàng)建一個名為application-prod.properties的文件,其內(nèi)容如下:
server.port=8083spring.datasource.url=jdbc:mysql://localhost:3306spring.datasource.username=root
spring.datasource.password=
spring.datasource.name=managing_flyway_migrations_prodspring.flyway.locations=classpath:/db/migration/shared,classpath:/db/migration/prod
spring.flyway.schemas=${spring.datasource.name}
3- Create the migrations files under src/main/resources/db/migration.3.1- Under shared, create a file called V1_1__Initial_Schema.sql with the following content:
3-在src/main/resources/db/migration下創(chuàng)建遷移文件.3.1-在shared ,創(chuàng)建一個名為V1_1__Initial_Schema.sql的文件,其內(nèi)容如下:
CREATE TABLE roles (id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(100),PRIMARY KEY (id)
);CREATE TABLE users (
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(255),
role_id BIGINT NOT NULL,PRIMARY KEY (id),FOREIGN KEY (role_id) REFERENCES roles (id)
);CREATE TABLE content_categories (
id BIGINT NOT NULL,
name VARCHAR(255) NOT NULL,PRIMARY KEY (id)
);CREATE TABLE content (
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(255),
category_id BIGINT NOT NULL,PRIMARY KEY (id),FOREIGN KEY (category_id) REFERENCES content_categories(id)
);
3.2- Under shared, create a file called V1_2__Add_content_topic.sql with the following content:
3.2-在shared ,創(chuàng)建一個名為V1_2__Add_content_topic.sql的文件,其內(nèi)容如下:
CREATE TABLE content_topics (id BIGINT NOT NULL,
name VARCHAR(255) NOT NULL,PRIMARY KEY (id)
);ALTER TABLE content
ADD COLUMN topic_id BIGINT,
ADD CONSTRAINT FOREIGN KEY (topic_id) REFERENCES content_topics(id);
3.3- Under shared, create a file called R__1_Master_Data.sql with the following content:
3.3-在shared ,創(chuàng)建一個名為R__1_Master_Data.sql的文件,其內(nèi)容如下:
INSERT INTOroles (id, name)
VALUES (1, 'System'), (2, 'Admin'), (3, 'User')
ON DUPLICATE KEY UPDATE id=id, name=VALUES(`name`);INSERT INTO
content_categories (id, name)
VALUES (1, 'Category 1'), (2, 'Category 2')
ON DUPLICATE KEY UPDATE id=id, name=VALUES(`name`);# INSERT statements for the First Run
# Comment out for the Third Run
####################################################################
INSERT INTO
content (id, name, category_id)
VALUES (1, 'Content 1.1', 1), (2, 'Content 1.2', 1),
(3, 'Content 2.1', 2), (4, 'Content 2.2', 2)
ON DUPLICATE KEY UPDATE id=id, name=VALUES(`id`), category_id=VALUES(`category_id`);
##################################################################### INSERT statements for the Third Run
# Uncomment for the Third Run
####################################################################
# INSERT INTO
# content_topics (id, name)
# VALUES (1, 'Topic 1'), (2, 'Topic 2')
# ON DUPLICATE KEY UPDATE id=id, name=VALUES(`name`);
#
# INSERT INTO
# content (id, name, category_id, topic_id)
# VALUES (1, 'Content 1.1', 1, 1), (2, 'Content 1.2', 1, 2),
# (3, 'Content 2.1', 2, 2), (4, 'Content 2.2', 2, 1)
# ON DUPLICATE KEY UPDATE id=id, name=VALUES(`name`), category_id=VALUES(`category_id`), topic_id=VALUES(`topic_id`);
####################################################################
Note: Notice that this migration starts with an R. This is what makes it a repeatable migration.
注意 :請注意,此遷移以R.開頭R.這就是使其成為可重復(fù)遷移的原因。
Note 2: Notice that the number in the name of the migration is neither necessary nor does it mean a specific version. I’m using numbers in the description of data migrations simply to order their execution. Flyway executes versioned migrations according to their versions first, then repeatable migrations alphabetically according to their descriptions.
注2 :請注意,遷移名稱中的數(shù)字既不是必需的,也不表示特定版本。 我在數(shù)據(jù)遷移的描述中使用數(shù)字只是為了命令執(zhí)行。 Flyway首先根據(jù)其版本執(zhí)行版本化的遷移,然后根據(jù)其描述按字母順序執(zhí)行可重復(fù)的遷移。
3.4- Under non-prod, create a file called R__2_Non_prod_login.sql with the following content:
3.4-在non-prod ,創(chuàng)建一個名為R__2_Non_prod_login.sql的文件,其內(nèi)容如下:
INSERT INTOusers (id, name, role_id)
VALUES (201, 'SuperAdmin', 1)
ON DUPLICATE KEY UPDATE id=id, name=VALUES(`name`), role_id=VALUES(`role_id`);
3.5- Under dev, create a file called R__3_Dev_login.sql with the following content:
3.5-在dev之下,創(chuàng)建一個名為R__3_Dev_login.sql的文件,其內(nèi)容如下:
INSERT INTOusers (id, name, role_id)
VALUES (301, 'Developer 1', 2), (302, 'Developer 2', 2)
ON DUPLICATE KEY UPDATE id=id, name=VALUES(`name`), role_id=VALUES(`role_id`);
3.6- Under staging, create a file called R__3_Staging_login.sql with the following content:
3.6-在staging ,創(chuàng)建一個名為R__3_Staging_login.sql的文件,其內(nèi)容如下:
INSERT INTOusers (id, name, role_id)
VALUES (301, 'QA 1', 3), (302, 'QA 2', 3)
ON DUPLICATE KEY UPDATE id=id, name=VALUES(`name`), role_id=VALUES(`role_id`);
By now, we have all the code and configurations we need for our first run.
到現(xiàn)在為止,我們已經(jīng)擁有了第一次運(yùn)行所需的所有代碼和配置。
Photo by Fabio Comparelli on Unsplash Fabio Comparelli在Unsplash上拍攝的照片第一次運(yùn)行 (First Run)
In this first run, we’ll execute the 1.1 versioned migration alongside the other repeated ones to simulate a deployment with the initial database schema and data.
在第一次運(yùn)行中,我們將與其他重復(fù) 版本一起執(zhí)行1.1 版本的遷移,以模擬具有初始數(shù)據(jù)庫架構(gòu)和數(shù)據(jù)的部署。
The two important locations to differentiate between runs in these tests are the Flyway target in application.properties and the INSERT statements in R__1_Master_Data.sql. If you’re using the accompanying GitHub repository, make sure you’re on the first-run branch.
在這些測試運(yùn)行之間的區(qū)分這兩個重要的位置是在遷飛目標(biāo)application.properties ,并在INSERT語句R__1_Master_Data.sql 。 如果您使用隨附的GitHub存儲庫,請確保您位于first-run分支。
測試`dev`配置文件 (Testing the `dev` Profile)
Run the application with the dev profile active:
在dev配置文件處于活動狀態(tài)的情況下運(yùn)行應(yīng)用程序:
mvn spring-boot:run -Dspring.profiles.active=devBy now, we expect a number of things:* The versioned migration V1_1__Initial_Schema.sql was applied.* The versioned migration V1_2__Add_content_topic.sql was not applied (since we have the target set to 1.1).* The shared repeated migration R__1_Master_Data.sql was applied.* The non-prod repeated migration R__2_Non_prod_login.sql was applied.* The dev repeated migration R__3_Dev_login.sql was applied.
到目前為止,我們期望發(fā)生以下事情:*應(yīng)用了版本化的遷移V1_1__Initial_Schema.sql 。*沒有應(yīng)用版本化的遷移V1_2__Add_content_topic.sql (因?yàn)槲覀儗⒛繕?biāo)設(shè)置為1.1 )。*共享的重復(fù)遷移R__1_Master_Data.sql是*已應(yīng)用非產(chǎn)品重復(fù)遷移R__2_Non_prod_login.sql 。*已應(yīng)用dev 重復(fù)遷移R__3_Dev_login.sql 。
Use the Dev Database
使用開發(fā)數(shù)據(jù)庫
USE managing_flyway_migrations_dev;Check the History Table
查看歷史記錄表
To verify this, we check the flyway_schema_history that Flyway would’ve created by running the following inside our database server:
為了驗(yàn)證這一點(diǎn),我們檢查flyway_schema_history 可以通過在數(shù)據(jù)庫服務(wù)器內(nèi)部運(yùn)行以下命令來創(chuàng)建:
SELECT installed_rank, version, description, success FROM flyway_schema_history;The output of the SELECT statement above should look as follows:
上面的SELECT語句的輸出應(yīng)如下所示:
+----------------+---------+------------------+---------+| installed_rank | version | description | success |
+----------------+---------+------------------+---------+
| 1 | 1.1 | Initial Schema | 1 |
| 2 | NULL | 1 Master Data | 1 |
| 3 | NULL | 2 Non prod login | 1 |
| 4 | NULL | 3 Dev login | 1 |
+----------------+---------+------------------+---------+
Check the Content Table
檢查內(nèi)容表
The content table should contain the records we inserted in the Master Data as follows:
內(nèi)容表 應(yīng)該包含我們插入到主數(shù)據(jù)中的記錄,如下所示:
SELECT * FROM content;This should output:
這應(yīng)該輸出:
+----+-------------+-------------+| id | name | category_id |
+----+-------------+-------------+
| 1 | Content 1.1 | 1 |
| 2 | Content 1.2 | 1 |
| 3 | Content 2.1 | 2 |
| 4 | Content 2.2 | 2 |
+----+-------------+-------------+
Check the Users Table
檢查用戶表
In the users table, we should see records from both the Non-production Login (SuperAdmin) as well as the Dev Login migrations we defined. Run the command:
在用戶表中,我們應(yīng)該看到非生產(chǎn)登錄 (SuperAdmin)以及我們定義的開發(fā)登錄的遷移記錄。 運(yùn)行命令:
SELECT * FROM users;This should output:
這應(yīng)該輸出:
+-----+-------------+---------+| id | name | role_id |
+-----+-------------+---------+
| 201 | SuperAdmin | 1 |
| 301 | Developer 1 | 2 |
| 302 | Developer 2 | 2 |
+-----+-------------+---------+
I leave testing the staging profile to the reader as it’s almost identical to the tests described in this section.
我將測試staging配置文件留給讀者,因?yàn)樗鼛缀跖c本節(jié)中描述的測試相同。
Now, let’s move on to testing production!
現(xiàn)在,讓我們繼續(xù)測試生產(chǎn)!
測試` prod配置文件 (Testing the `prod` Profile)
Run the application with the prod profile active:
在prod配置文件處于活動狀態(tài)的情況下運(yùn)行應(yīng)用程序:
mvn spring-boot:run -Dspring.profiles.active=prodBy now, we expect a number of things:* The versioned migration V1_1__Initial_Schema.sql was applied.* The versioned migration V1_2__Add_content_topic.sql was not applied.* The shared repeated migration R__1_Master_Data.sql was applied.
到現(xiàn)在為止,我們期待一些事情:*本版本遷移V1_1__Initial_Schema.sql 。應(yīng)用*的版本控制的遷移V1_2__Add_content_topic.sql 。不適用*共享重復(fù)遷移R__1_Master_Data.sql應(yīng)用。
Use the Prod Database
使用產(chǎn)品數(shù)據(jù)庫
USE managing_flyway_migrations_prod;Check the History Table
查看歷史記錄表
To verify this, we check the flyway_schema_history that Flyway would’ve created by running the following inside our database server:
為了驗(yàn)證這一點(diǎn),我們檢查flyway_schema_history 可以通過在數(shù)據(jù)庫服務(wù)器內(nèi)部運(yùn)行以下命令來創(chuàng)建:
SELECT installed_rank, version, description, success FROM flyway_schema_history;The output of the SELECT statement above should look as follows:
上面的SELECT語句的輸出應(yīng)如下所示:
+----------------+---------+----------------+---------+| installed_rank | version | description | success |
+----------------+---------+----------------+---------+
| 1 | 1.1 | Initial Schema | 1 |
| 2 | NULL | 1 Master Data | 1 |
+----------------+---------+----------------+---------+
Notice that in production, we don’t have any of the test credentials defined in non-prod, dev, or staging.
請注意,在生產(chǎn)環(huán)境中,我們沒有在非生產(chǎn),開發(fā)或暫存中定義的任何測試憑據(jù)。
Check the Content Table
檢查內(nèi)容表
The content table should contain the records we inserted in the Master Data similar to what we saw in dev:
內(nèi)容表 應(yīng)該包含我們插入到主數(shù)據(jù)中的記錄,類似于在dev看到的記錄:
SELECT * FROM content;This should output:
這應(yīng)該輸出:
+----+-------------+-------------+| id | name | category_id |
+----+-------------+-------------+
| 1 | Content 1.1 | 1 |
| 2 | Content 1.2 | 1 |
| 3 | Content 2.1 | 2 |
| 4 | Content 2.2 | 2 |
+----+-------------+-------------+
Check the Users Table
檢查用戶表
The users table should be empty:
用戶表應(yīng)為空:
SELECT * FROM users;This should output:
這應(yīng)該輸出:
Empty set (0.00 sec)Photo by Chander R on Unsplash Chander R在Unsplash上的照片第二次跑 (Second Run)
In this run, we simulate an application restart or a deployment that contains no migration changes. Here, we’re really testing Flyway’s behavior.
在此運(yùn)行中,我們模擬應(yīng)用程序重新啟動或不包含任何遷移更改的部署。 在這里,我們正在測試Flyway的行為。
測試`dev`配置文件 (Testing the `dev` Profile)
Stop and rerun the dev application:
停止并重新運(yùn)行dev應(yīng)用程序:
mvn spring-boot:run -Dspring.profiles.active=dev測試` prod配置文件 (Testing the `prod` Profile)
Stop and rerun the prod application as well:
也停止并重新運(yùn)行prod應(yīng)用程序:
mvn spring-boot:run -Dspring.profiles.active=prod結(jié)果 (Results)
In the stream of logs that Spring generates in each run, look for a line containing the following:
在Spring每次運(yùn)行中生成的日志流中,查找包含以下內(nèi)容的行:
Schema `managing_flyway_migrations_dev` is up to date. No migration necessary.This tells us that Flyway detected that no changes were made to the migrations, and therefore it took no action. Notice that even repeatable migrations were’s re-applied by Flyway; this is because the files, and therefore their checksums, didn’t change.
這告訴我們Flyway檢測到未對遷??移進(jìn)行任何更改,因此未采取任何措施。 請注意, Flyway甚至重新應(yīng)用了可重復(fù)的遷移。 這是因?yàn)槲募捌湫r?yàn)和沒有發(fā)生變化。
Feel free to explore records in the tables after the restart to verify that nothing actually changed before moving on to the Third Run.
重新啟動后,請隨意瀏覽表中的記錄,以確保在進(jìn)行第三次運(yùn)行之前沒有任何實(shí)際更改。
Andrew Tanglao on 安德魯·唐勞 ( UnsplashUnderlash)第三輪 (Third Run)
Now, let’s simulate a deployment with changes made to both versioned and repeatable migrations.
現(xiàn)在,讓我們模擬對版本化遷移和可重復(fù)遷移所做的更改的部署。
In the application.propertiesfile, change the spring.flyway.target property to 1.2 or delete it altogether. This will cause Flyway to apply the second versioned migration we have; V1_2__Add_content_topic.sql.
在application.properties文件中,將spring.flyway.target屬性更改為1.2或?qū)⑵渫耆珓h除。 這將導(dǎo)致Flyway應(yīng)用我們擁有的第二個版本化的遷移; V1_2__Add_content_topic.sql 。
In the R__1_Master_Data.sql, comment out the block for the First Run, and uncomment the one for the Third Run, as mentioned. Notice that in an actual application, you’d really be modifying the existing code instead of the commenting stuff.
R__1_Master_Data.sql ,在R__1_Master_Data.sql ,注釋掉“ 第一次運(yùn)行”的塊,并取消注釋“ 第三次運(yùn)行”的塊。 注意,在實(shí)際的應(yīng)用程序中,您實(shí)際上是在修改現(xiàn)有代碼,而不是注釋內(nèi)容。
If you’re using the GitHub repository, simply checkout the third-run branch.
如果您使用的是GitHub存儲庫,只需簽出third-run分支。
測試`dev`配置文件 (Testing the `dev` Profile)
Similar to the previous steps, stop and rerun the dev application:
與前面的步驟類似,停止并重新運(yùn)行dev應(yīng)用程序:
mvn spring-boot:run -Dspring.profiles.active=devBy now, we expect a number of things:* The versioned migration V1_1__Initial_Schema.sql was not re-applied.* The versioned migration V1_2__Add_content_topic.sql was applied.* The shared repeated migration R__1_Master_Data.sql was re-applied (since it was changed).* The non-prod repeated migration R__2_Non_prod_login.sql was not re-applied (since it was not changed).* The dev repeated migration R__3_Dev_login.sql was not re-applied.
到現(xiàn)在為止,我們期待一些事情:*的版本控制的遷移V1_1__Initial_Schema.sql 。 沒有重新申請*的版本控制的遷移V1_2__Add_content_topic.sql 。應(yīng)用*共享重復(fù)遷移R__1_Master_Data.sql被重新應(yīng)用(因?yàn)樗桓淖?。* 未重新應(yīng)用非產(chǎn)品重復(fù)遷移R__2_Non_prod_login.sql (因?yàn)槲锤?。* 未重新應(yīng)用開發(fā)人員重復(fù)遷移R__3_Dev_login.sql 。
Use the Dev Database
使用開發(fā)數(shù)據(jù)庫
USE managing_flyway_migrations_dev;Check the History Table
查看歷史記錄表
Similar to the previous tests, run:
與先前的測試類似,運(yùn)行:
SELECT installed_rank, version, description, success FROM flyway_schema_history;The output of the SELECT statement above should look as follows:
上面的SELECT語句的輸出應(yīng)如下所示:
+----------------+---------+-------------------+---------+| installed_rank | version | description | success |
+----------------+---------+-------------------+---------+
| 1 | 1.1 | Initial Schema | 1 |
| 2 | NULL | 1 Master Data | 1 |
| 3 | NULL | 2 Non prod login | 1 |
| 4 | NULL | 3 Dev login | 1 |
| 5 | 1.2 | Add content topic | 1 |
| 6 | NULL | 1 Master Data | 1 |
+----------------+---------+-------------------+---------+
Notice the 1.2 versioned migration at the rank 5 as well as the re-application of the modified Master Data migration at 6.
注意排名5的1.2 版本遷移以及重新應(yīng)用修改后的Master Data遷移6 。
Check the Content Table
檢查內(nèi)容表
The content table should contain the records we inserted in the modified Master Data, including the new topic_id column introduced by the new migrations:
內(nèi)容表 應(yīng)包含我們在修改后的主數(shù)據(jù)中插入的記錄,包括新遷移引入的新topic_id列:
SELECT * FROM content;This should output:
這應(yīng)該輸出:
+----+-------------+-------------+----------+| id | name | category_id | topic_id |
+----+-------------+-------------+----------+
| 1 | Content 1.1 | 1 | 1 |
| 2 | Content 1.2 | 1 | 2 |
| 3 | Content 2.1 | 2 | 2 |
| 4 | Content 2.2 | 2 | 1 |
+----+-------------+-------------+----------+
Check the Users Table
檢查用戶表
The users table wouldn’t have changed since the last run:
自上次運(yùn)行以來, users表不會更改:
SELECT * FROM users;This should output:
這應(yīng)該輸出:
+-----+-------------+---------+| id | name | role_id |
+-----+-------------+---------+
| 201 | SuperAdmin | 1 |
| 301 | Developer 1 | 2 |
| 302 | Developer 2 | 2 |
+-----+-------------+---------+
測試` prod配置文件 (Testing the `prod` Profile)
Similarly, stop and rerun the prod application:
同樣,停止并重新運(yùn)行prod應(yīng)用程序:
mvn spring-boot:run -Dspring.profiles.active=prodBy now, we expect the following:* The versioned migration V1_1__Initial_Schema.sql was not re-applied.* The versioned migration V1_2__Add_content_topic.sql was applied.* The shared repeated migration R__1_Master_Data.sql was re-applied.
到現(xiàn)在為止,我們預(yù)計如下:*的版本控制的遷移V1_1__Initial_Schema.sql 沒有再次應(yīng)用*的版本控制的遷移。 V1_2__Add_content_topic.sql應(yīng)用*共享重復(fù)遷移。 R__1_Master_Data.sql被重施。
Use the Prod Database
使用產(chǎn)品數(shù)據(jù)庫
USE managing_flyway_migrations_prod;Check the History Table
查看歷史記錄表
Two new records should show in the flyway_schema_historytable:
兩個新記錄應(yīng)顯示在flyway_schema_history表中:
SELECT installed_rank, version, description, success FROM flyway_schema_history;The output of the SELECT statement above should look as follows:
上面的SELECT語句的輸出應(yīng)如下所示:
+----------------+---------+-------------------+---------+| installed_rank | version | description | success |
+----------------+---------+-------------------+---------+
| 1 | 1.1 | Initial Schema | 1 |
| 2 | NULL | 1 Master Data | 1 |
| 3 | 1.2 | Add content topic | 1 |
| 4 | NULL | 1 Master Data | 1 |
+----------------+---------+-------------------+---------+
Check the Content Table
檢查內(nèi)容表
Similar to dev, the content records should contain the new topic_id column:
與dev類似, 內(nèi)容記錄應(yīng)包含新的topic_id列:
SELECT * FROM content;This should output:
這應(yīng)該輸出:
+----+-------------+-------------+----------+| id | name | category_id | topic_id |
+----+-------------+-------------+----------+
| 1 | Content 1.1 | 1 | 1 |
| 2 | Content 1.2 | 1 | 2 |
| 3 | Content 2.1 | 2 | 2 |
| 4 | Content 2.2 | 2 | 1 |
+----+-------------+-------------+----------+
Check the Users Table
檢查用戶表
The users table should still be empty:
用戶表仍應(yīng)為空:
SELECT * FROM users;This should output:
這應(yīng)該輸出:
Empty set (0.00 sec)Photo by Aw Creative on Unsplash圖片由Aw Creative在Unsplash上拍攝干凈運(yùn)行 (Clean Run)
Finally, let’s simulate a fresh installation of the application at this stage. This simulates how migrations would work in a fresh environment with an empty database or when the project is freshly set up on a new local development machine.
最后,讓我們在此階段模擬該應(yīng)用程序的全新安裝。 這模擬了遷移如何在具有空數(shù)據(jù)庫的新環(huán)境中工作,或者何時在新的本地開發(fā)計算機(jī)上新設(shè)置了項(xiàng)目。
Let’s use the staging environment here for a change. We’ll pretend that we’re just now setting up staging with the current code and a fresh database:
讓我們在這里使用staging環(huán)境進(jìn)行更改。 我們假裝我們現(xiàn)在正在使用當(dāng)前代碼和一個新數(shù)據(jù)庫來設(shè)置staging :
DROP DATABASE managing_flyway_migrations_staging;CREATE DATABASE managing_flyway_migrations_staging;
Now run the staging application:
現(xiàn)在運(yùn)行staging應(yīng)用程序:
mvn spring-boot:run -Dspring.profiles.active=stagingBy this, we expect the following:* The versioned migration V1_1__Initial_Schema.sql was applied.* The versioned migration V1_2__Add_content_topic.sql was applied.* The shared repeated migration R__1_Master_Data.sql was applied.* The non-prod repeated migration R__2_Non_prod_login.sql was applied.* The staging repeated migration R__3_Staging_login.sql was applied.
這樣,我們期望滿足以下條件:*應(yīng)用了版本化的遷移V1_1__Initial_Schema.sql 。*應(yīng)用了版本化的遷移V1_2__Add_content_topic.sql 。*應(yīng)用了共享的 重復(fù)遷移R__1_Master_Data.sql 。* 非產(chǎn)品 重復(fù)遷移R__2_Non_prod_login.sql被應(yīng)用了。 *已應(yīng)用分段 重復(fù)遷移R__3_Staging_login.sql 。
Use the Staging Database
使用登臺數(shù)據(jù)庫
USE managing_flyway_migrations_staging;Check the History Table
查看歷史記錄表
Two new records should show in the flyway_schema_historytable:
兩個新記錄應(yīng)顯示在flyway_schema_history表中:
SELECT installed_rank, version, description, success FROM flyway_schema_history;The output of the SELECT statement above should look as follows:
上面的SELECT語句的輸出應(yīng)如下所示:
+----------------+---------+-------------------+---------+| installed_rank | version | description | success |
+----------------+---------+-------------------+---------+
| 1 | 1.1 | Initial Schema | 1 |
| 2 | 1.2 | Add content topic | 1 |
| 3 | NULL | 1 Master Data | 1 |
| 4 | NULL | 2 Non prod login | 1 |
| 5 | NULL | 3 Staging login | 1 |
+----------------+---------+-------------------+---------+
Note: Notice that the Master Data migration is applied once. Also, notice that this works fine because repeated migrations are always run after all versioned migrations have been applied.
注意 :請注意, 主數(shù)據(jù)遷移僅應(yīng)用一次。 此外,請注意,此方法的效果很好,因?yàn)?strong>在應(yīng)用 所有 版本化的遷移后始終會重復(fù)運(yùn)行遷移。
Check the Content Table
檢查內(nèi)容表
The content table should already have all changes, including the topic_id column:
內(nèi)容表應(yīng)該已經(jīng)進(jìn)行了所有更改,包括topic_id列:
SELECT * FROM content;This should output:
這應(yīng)該輸出:
+----+-------------+-------------+----------+| id | name | category_id | topic_id |
+----+-------------+-------------+----------+
| 1 | Content 1.1 | 1 | 1 |
| 2 | Content 1.2 | 1 | 2 |
| 3 | Content 2.1 | 2 | 2 |
| 4 | Content 2.2 | 2 | 1 |
+----+-------------+-------------+----------+
Check the Users Table
檢查用戶表
The users table should have records from both the Non-production Login and Staging Login migrations:
users表應(yīng)該具有非生產(chǎn)登錄和暫存登錄遷移的記錄:
SELECT * FROM users;This should output:
這應(yīng)該輸出:
+-----+------------+---------+| id | name | role_id |
+-----+------------+---------+
| 201 | SuperAdmin | 1 |
| 301 | QA 1 | 3 |
| 302 | QA 2 | 3 |
+-----+------------+---------+
代碼 (The Code)
If you’d like a test drive with minimal effort, I’ve put together the same setup handy on GitHub: https://github.com/sayadi/managing-flyway-migrations-spring-boot.
如果您想以最小的努力進(jìn)行測試,我可以在GitHub上方便地進(jìn)行相同的設(shè)置: https : //github.com/sayadi/managing-flyway-migrations-spring-boot 。
最后的話 (A Final Word)
While this setup works, it is something I dreamt up for this article as a solution to a repeated problem I see. However, we haven’t had a chance to test this on a production application yet.
盡管此設(shè)置有效,但我為本文構(gòu)想的是作為我遇到的重復(fù)問題的解決方案。 但是,我們還沒有機(jī)會在生產(chǎn)應(yīng)用程序上對此進(jìn)行測試。
If you do end up using it in a real setup, do let me know in the comments below what works for you, what doesn’t, and what changes you might have had to do. Thanks for reading!
如果您確實(shí)要在實(shí)際設(shè)置中使用它,請?jiān)谙旅娴脑u論中讓我知道什么對您有用,什么不起作用以及您可能需要進(jìn)行哪些更改。 謝謝閱讀!
翻譯自: https://levelup.gitconnected.com/a-suggestion-on-managing-data-changes-in-spring-boot-using-flyway-b87cf87f8e88
flyway spring
總結(jié)
以上是生活随笔為你收集整理的flyway spring_关于使用Flyway在Spring Boot中管理数据更改的建议的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 破局:技术视野与规划
- 下一篇: Spring Boot系列之Thymel