{"id":70973,"date":"2020-02-23T00:58:26","date_gmt":"2020-02-22T21:58:26","guid":{"rendered":"https:\/\/prohoster.info\/blog\/kak-ne-vystrelit-sebe-v-nogu-ispolzuya-liquibase"},"modified":"2020-03-03T16:14:41","modified_gmt":"2020-03-03T13:14:41","slug":"kak-ne-vystrelit-sebe-v-nogu-ispolzuya-liquibase","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/kak-ne-vystrelit-sebe-v-nogu-ispolzuya-liquibase","title":{"rendered":"How to Avoid Shooting Yourself in the Foot with Liquibase","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Never has there been a time like this!<\/p>\n<p><\/p>\n<p>On our latest project, we decided to use Liquibase from the very beginning to avoid future problems. As it turned out, not all young team members know how to use it properly. I held an internal workshop that I later decided to turn into an article. <\/p>\n<p><\/p>\n<p>The article includes useful tips and descriptions of three of the most obvious traps one can fall into when working with relational database migration tools, particularly Liquibase. It is aimed at junior and mid-level Java developers, and may be of interest to more experienced developers for structuring and revisiting what they likely already know. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"How to Avoid Shooting Yourself in the Foot with Liquibase\" src=\"\/wp-content\/uploads\/2020\/02\/f8b3c9a456bde7aa123702fae132b4b8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Liquibase and Flyway are the leading competing technologies for version control of relational structures in the Java world. The former is completely free and is more often chosen for practical use, which is why Liquibase is the focus of this publication. However, some of the described practices may be universal, depending on your application's architecture. <\/p>\n<p><\/p>\n<p>Migrations of relational structures have emerged as a necessary method of addressing the poor flexibility of relational data stores. In the era of object-oriented programming, the style of working with databases implied that we would describe the schema once and never touch it again. But reality is always different; everything changes, and changes in table structures are required quite often. Naturally, the process can be painful and unpleasant. <\/p>\n<p><\/p>\n<p>I won't go into detail regarding the technology and instructions for adding the library to your project; plenty of articles have already been written on this topic:<\/p>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/460377\/\">Using Liquibase to manage database structure in a Spring Boot application. Part 1<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/460907\/\">Using Liquibase to manage database structure in a Spring Boot application. Part 2<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/436994\/\">Liquibase and Maven<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/330662\/\">Approaches to versioning database changes<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/271719\/\">Spring MVC\/Security, REST, Hibernate, Liquibase can be launched in two lines<\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<p>Additionally, there was already a great article on useful tips:<\/p>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/179425\/\">Using Liquibase without headaches. 10 tips from real development experience<\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<h2 id=\"sovety\">Tips<\/h2>\n<p><\/p>\n<p>I want to share my advice and comments that were born through the sweat, blood, and pain of solving migration problems.<\/p>\n<p><\/p>\n<h3 id=\"1--pered-rabotoy-sleduet-oznakomitsya-s-razdelom-luchshih-praktik-na-saytehttpswwwliquibaseorgbestpracticeshtml-liquibase\">1. Before starting work, you should familiarize yourself with the best practices section on <noindex><a rel=\"nofollow\" href=\"https:\/\/www.liquibase.org\/bestpractices.html\">the website<\/a><\/noindex> Liquibase<\/h3>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.liquibase.org\/bestpractices.html\">There<\/a><\/noindex> This explains simple yet crucial points that, without which, using the library could complicate your life. For instance, an unstructured approach to managing changelogs will eventually lead to confusion and broken migrations. If you roll out interdependent changes to the database schema and service logic separately, there's a high likelihood of encountering failing tests or a broken environment. Additionally, the recommendations for using Liquibase on the official website include a point about developing and verifying rollback scripts alongside the main migration scripts. Also, in the article, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/178665\/\">https:\/\/habr.com\/ru\/post\/178665\/<\/a><\/noindex> there are code examples related to migrations and the rollback mechanism. <\/p>\n<p><\/p>\n<h3 id=\"2-esli-nachali-ispolzovat-sredstva-migracii--ne-dopuskayte-manualnyh-ispravleniy-v-strukture-bazy\">2. Once you begin using migration tools, do not allow manual modifications to the database structure.<\/h3>\n<p><\/p>\n<p>As they say: \"Once Persil, always Persil.\" If your application's database is now managed by Liquibase, any manual changes immediately lead to an inconsistent state, making the trust level in the changelogs zero. Potential risks include several hours wasted on restoring the database; in the worst-case scenario, a ruined server. If you have an old-school DBA Architect on your team, patiently and thoughtfully explain to him how everything will turn out poorly if he simply edits the database as he sees fit using some SQL Developer. <\/p>\n<p><\/p>\n<h3 id=\"3-esli-chendzhset-uzhe-byl-zapushen-v-repozitoriy-izbegayte-redaktirovaniya\">3. If a changelog has already been pushed to the repository, avoid editing it.<\/h3>\n<p><\/p>\n<p>If another developer pulls and applies a changelog that is later edited, he will certainly speak of you fondly when he encounters an error at application startup. If editing the changelog somehow leaks into development, you'll have to navigate a slippery path of hotfixes. The crux of the problem lies in change validation by hash \u2014 the fundamental mechanism of Liquibase. When the code of a changelog is edited, its hash changes. Editing changelogs is only feasible when there's an option to redeploy the entire database from scratch without data loss. In such cases, refactoring SQL or XML code can, on the contrary, make life easier and migrations more readable. An example would be when the original database schema was agreed upon within the team at the application's start. <\/p>\n<p><\/p>\n<h3 id=\"4--imey-proverennye-bekapy-baz-dannyh-esli-eto-vozmozhno\">4. Have verified database backups, if possible<\/h3>\n<p><\/p>\n<p>Here, I think everything is clear. In case the migration fails, everything can be restored. Liquibase has a rollback tool, but the rollback scripts are also written by the developer, and there can be issues with them just as likely as with the main changelist scripts. This means being cautious with backups is beneficial in any case. <\/p>\n<p><\/p>\n<h3 id=\"5-ispolzuy-proverennye-bekapy-baz-dannyh-v-razrabotke-esli-eto-vozmozhno\">5. Use verified database backups in development, if possible<\/h3>\n<p><\/p>\n<p>If it doesn\u2019t contradict contracts and privacy, there are no personal data in the database, and it doesn't weigh as much as two suns \u2014 before applying migration on live servers, you can test how it works on the developer's machine and identify almost 100% of potential migration issues. <\/p>\n<p><\/p>\n<h3 id=\"6-obschaysya-s-drugimi-razrabotchikami-v-komande\">6. Communicate with other developers in the team<\/h3>\n<p><\/p>\n<p>In a properly organized development process, everyone in the team knows what others are working on. In reality, this often isn\u2019t the case, so if you are preparing changes to the database structure as part of your task, it\u2019s advisable to additionally notify the entire team about it. If someone is making changes in parallel \u2014 you should organize yourselves carefully. It\u2019s worth communicating with colleagues even after completing the work, not just at the start. Many potential issues with changelists can be resolved during the code review phase. <\/p>\n<p><\/p>\n<h3 id=\"7-dumay-chto-delaesh\">7. Think about what you\u2019re doing!<\/h3>\n<p><\/p>\n<p>Seemingly an obvious piece of advice applicable to any situation. However, many problems could be avoided if the developer analyzed once more what they are doing and how it might affect others. Working with migrations always requires extra attention and care. <\/p>\n<p><\/p>\n<h2 id=\"lovushki\">Traps<\/h2>\n<p><\/p>\n<p>Now let\u2019s look at typical pitfalls you can encounter if you don\u2019t follow the above advice, and what should be done?<\/p>\n<p><\/p>\n<h3 id=\"situaciya-1-dva-razrabotchika-pytayutsya-odnovremenno-dobavlyat-novye-chendzhsety\">Situation 1. Two developers are trying to add new changelists at the same time<\/h3>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"How to Avoid Shooting Yourself in the Foot with Liquibase\" src=\"\/wp-content\/uploads\/2020\/02\/20706fc970510bc06634fa001a4c7ceb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVasya and Petya want to create changelist version 4, unaware of each other. They made changes to the database structure and submitted pull requests with different changelist files. The following mechanism of actions is proposed:<\/p>\n<p><\/p>\n<h4 id=\"kak-reshat\">How to resolve<\/h4>\n<p><\/p>\n<ol>\n<li>Somehow, colleagues need to agree on the order in which their changelists should be applied; for example, Petya's should be applied first. <\/li>\n<li>Someone needs to apply the second changeSet to themselves and mark Vasya's changeSet with version 5. This can be done through Cherry Pick or a careful merge. <\/li>\n<li>After making changes, it's essential to verify the validity of the actions taken.<br \/>\nIn fact, Liquibase mechanisms will allow having two changeSets of version 4 in the repository, so everything can be left as is. This means you will simply have two changes of version 4 with different names. With this approach, it becomes very challenging to navigate in the database versions later on. <\/li>\n<\/ol>\n<p><\/p>\n<p>Additionally, Liquibase, like the hobbits' home, holds many secrets. One of them is the validCheckSum key, which appeared with version 1.7 and allows specifying a valid checksum value for a specific changeSet regardless of what is stored in the database. Documentation <noindex><a rel=\"nofollow\" href=\"https:\/\/www.liquibase.org\/documentation\/changeset.html\">https:\/\/www.liquibase.org\/documentation\/changeset.html<\/a><\/noindex> states the following:<\/p>\n<p><\/p>\n<blockquote><p>Add a checksum that is deemed valid for this changeSet, regardless of what is stored in the database. This is primarily used when you need to modify a changeSet and want to avoid errors on databases where it has already been executed (not a recommended procedure).<\/p><\/blockquote>\n<p>Yes, this procedure is not recommended. But sometimes a powerful white mage is skilled in dark techniques as well. <\/p>\n<p><\/p>\n<h3 id=\"situaciya-2-migraciya-kotoraya-zavisit-ot-dannyh\">Situation 2. Migration that depends on data.<\/h3>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"How to Avoid Shooting Yourself in the Foot with Liquibase\" src=\"\/wp-content\/uploads\/2020\/02\/31a6eebb55278c0631115bf16483c7b8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Assume you don't have the ability to use backups from live servers. Petya created a changeSet, tested it locally, and with full confidence in his correctness made a pull request to the development branch. The project lead double-checked whether Petya had verified it, and then merged it. However, the deployment on the development server failed.<\/p>\n<p><\/p>\n<p>In fact, this is possible, and no one is immune to it. It happens when modifications to table structures are somehow tied to specific data in the database. Obviously, if Petya's database is filled only with test data, it may not cover all problematic cases. For example, when deleting a table, it becomes clear that there are entries in other tables referencing the deleted one via Foreign Key. Or, when changing a column type, it is discovered that not 100% of data can be converted to the new type. <\/p>\n<p><\/p>\n<h4 id=\"kak-reshat-1\">How to resolve<\/h4>\n<p><\/p>\n<ul>\n<li>Write special scripts that will be applied once along with the migration to format the data correctly. This is a general approach to solving the problem of transferring data into new structures after migrations are applied, but something similar can be applied beforehand in certain cases. Of course, this approach is not always available, as editing data on live servers can be dangerous and even detrimental. <\/li>\n<li>Another complex route is to edit the existing changset. The challenge here is that all databases where it has already been applied in its current form will need to be restored. It is quite possible that the entire backend team will have to locally rebuild the database from scratch. <\/li>\n<li>And the most universal way is to transfer the problem with the data to the developer's environment, recreating the same situation and adding a new changset to the broken one, which will allow bypassing the issue.<br \/>\n<img decoding=\"async\" alt=\"How to Avoid Shooting Yourself in the Foot with Liquibase\" src=\"\/wp-content\/uploads\/2020\/02\/b5d28a940a7a35b6cd7a819a8e68f027.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<\/ul>\n<p><\/p>\n<p>Overall, the more the data composition of the database resembles that of the production server, the lower the likelihood that migration issues will escalate significantly. And, of course, before submitting the changset to the repository, it is worth considering multiple times whether it will break anything. <\/p>\n<p><\/p>\n<h3 id=\"situaciya-3-liquibase-nachinaet-primenyatsya-uzhe-posle-vyhoda-v-prodakshn\">Situation 3. Liquibase starts to be applied after moving to production.<\/h3>\n<p><\/p>\n<p>Suppose the team lead asked Petya to integrate Liquibase into the project, however, the project is already in production and there is an existing database structure.<\/p>\n<p><\/p>\n<p>Accordingly, the problem lies in the necessity that on any new servers or developer machines, the data tables need to be recreated from scratch, while the existing environment must remain in a consistent state, being ready to accept new changsets. <\/p>\n<p><\/p>\n<h4 id=\"kak-reshat-2\">How to resolve<\/h4>\n<p><\/p>\n<p>There are also several ways to approach this:<\/p>\n<p><\/p>\n<ul>\n<li>The first and most obvious way is to have a separate script that must be manually applied when initializing a new environment. <\/li>\n<li>The second \u2014 less obvious \u2014 is to have a Liquibase migration that is located in a different Liquibase Context and apply it. More details about Liquibase Context can be read here: <noindex><a rel=\"nofollow\" href=\"https:\/\/www.liquibase.org\/documentation\/contexts.html\">https:\/\/www.liquibase.org\/documentation\/contexts.html<\/a><\/noindex>. Overall, this is an interesting mechanism that can be successfully applied, for example, for testing. <\/li>\n<li>The third method consists of several steps. First, a migration must be created for the existing tables. Then it should be applied in some environment, and this will yield its hash value. The next step is to initialize empty Liquibase tables on our non-empty server, and manually insert a record in the changelog table indicating a 'presumably applied' changelog with the changes that already exist in the database. This way, on the existing server, the history will start from version 2, and all new environments will behave identically.<br \/>\n<img decoding=\"async\" alt=\"How to Avoid Shooting Yourself in the Foot with Liquibase\" src=\"\/wp-content\/uploads\/2020\/02\/78881ee56a6ee3ba4e0cd1089598c3c7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"situaciya-4-migracii-stanovyatsya-ogromnymi-i-ne-uspevayut-vypolnyatsya\">Situation 4. Migrations become huge and fail to execute in time.<\/h3>\n<p><\/p>\n<p>At the beginning of service development, Liquibase is typically used as an external dependency, and all migrations are processed when the application starts. However, over time, you may encounter the following scenarios:<\/p>\n<p><\/p>\n<ul>\n<li>Migrations become extensive and take a long time to execute.<\/li>\n<li>There is a need for migration in distributed environments, for example, on several database server instances simultaneously.<br \/>\nIn such cases, prolonged migration application will result in a timeout when starting the application. Additionally, applying migrations for each application instance separately may lead to different servers being in an unsynchronized state. <\/li>\n<\/ul>\n<p><\/p>\n<h4 id=\"kak-reshat-3\">How to resolve<\/h4>\n<p><\/p>\n<p>In these cases, your project is already large, possibly even mature, and Liquibase starts to act as a separate external tool. The thing is, Liquibase as a library is packaged in a jar file and can operate as a dependency within the project or autonomously. <\/p>\n<p><\/p>\n<p>In standalone mode, the application of migrations can be delegated to your CI\/CD environment or to the strong shoulders of your deployment specialists. For this, the Liquibase command line will be necessary. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.liquibase.org\/documentation\/command_line.html\">https:\/\/www.liquibase.org\/documentation\/command_line.html<\/a><\/noindex>In this mode, there's an opportunity to launch the application only after all necessary migrations have been completed.<\/p>\n<p><\/p>\n<h2 id=\"vyvod\">Output<\/h2>\n<p><\/p>\n<p>In fact, there can be many more pitfalls when dealing with database migrations, and many of them require a creative approach. It's important to understand that if you use the tool correctly, most of these pitfalls can be avoided. Personally, I have encountered all of the mentioned issues in various forms, and some were the result of my mistakes. Mainly, this happens due to carelessness, but sometimes it\u2019s due to a lack of skill in using the tool.<\/p>\n<p>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/epam_systems\/blog\/489198\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0431\u044b\u043b\u043e, \u0438 \u0432\u043e\u0442 \u043e\u043f\u044f\u0442\u044c! \u041d\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Liquibase \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c. \u041a\u0430\u043a \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u043d\u0435 \u0432\u0441\u0435 \u043c\u043e\u043b\u043e\u0434\u044b\u0435 \u0447\u043b\u0435\u043d\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0443\u043c\u0435\u044e\u0442 \u0435\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u042f \u043f\u0440\u043e\u0432\u0451\u043b \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0432\u043e\u0440\u043a\u0448\u043e\u043f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0442\u0435\u043c \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0432 \u0441\u0442\u0430\u0442\u044c\u044e. \u0421\u0442\u0430\u0442\u044c\u044f \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u043e\u0432\u0435\u0442\u044b \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0440\u0435\u0445 \u0441\u0430\u043c\u044b\u0445 \u044f\u0432\u043d\u044b\u0445 \u043b\u043e\u0432\u0443\u0448\u0435\u043a, \u0432 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":70974,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-70973","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0431\u044b\u043b\u043e, \u0438 \u0432\u043e\u0442 \u043e\u043f\u044f\u0442\u044c! \u041d\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Liquibase \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/kak-ne-vystrelit-sebe-v-nogu-ispolzuya-liquibase\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0430\u043a \u043d\u0435 \u0432\u044b\u0441\u0442\u0440\u0435\u043b\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u0432 \u043d\u043e\u0433\u0443, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Liquibase | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0431\u044b\u043b\u043e, \u0438 \u0432\u043e\u0442 \u043e\u043f\u044f\u0442\u044c! \u041d\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Liquibase \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/kak-ne-vystrelit-sebe-v-nogu-ispolzuya-liquibase\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-02-22T21:58:26+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-03-03T13:14:41+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47 How to avoid shooting yourself in the foot when using Liquibase | ProHoster","description":"It has never happened before, and here we are again! On our latest project, we decided to use Liquibase from the very beginning to avoid issues in the future.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/kak-ne-vystrelit-sebe-v-nogu-ispolzuya-liquibase","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0430\u043a \u043d\u0435 \u0432\u044b\u0441\u0442\u0440\u0435\u043b\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u0432 \u043d\u043e\u0433\u0443, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Liquibase | ProHoster","og:description":"\u041d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0431\u044b\u043b\u043e, \u0438 \u0432\u043e\u0442 \u043e\u043f\u044f\u0442\u044c! \u041d\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Liquibase \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c.","og:url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/kak-ne-vystrelit-sebe-v-nogu-ispolzuya-liquibase","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-02-22T21:58:26+00:00","article:modified_time":"2020-03-03T13:14:41+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"70973","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 19:10:24","updated":"2022-09-28 08:39:22","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/70973","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=70973"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/70973\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media\/70974"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=70973"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=70973"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=70973"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}