Hur du undviker att skjuta dig själv i foten med Liquibase

Aldrig hänt förut, och nu kör vi igen!

I vårt nästa projekt bestämde vi oss för att använda Liquibase från första början för att undvika problem i framtiden. Det visar sig att inte alla unga lagmedlemmar vet hur man använder det korrekt. Jag höll en intern workshop, som jag sedan bestämde mig för att göra om till en artikel.

Artikeln innehåller användbara tips och en beskrivning av de tre mest uppenbara fallgroparna som du kan hamna i när du arbetar med migreringsverktyg för relationsdatabas, i synnerhet Liquibase. Designad för Java-utvecklare på junior- och mellannivå; för mer erfarna utvecklare kan det vara av intresse för att strukturera och upprepa det som troligen redan är känt.

Hur du undviker att skjuta dig själv i foten med Liquibase

Liquibase och Flyway är de huvudsakliga konkurrerande teknologierna för att lösa versionskontrollproblem av relationsstrukturer i Java-världen. Den första är helt gratis, i praktiken väljs den oftast för användning, varför Liquibase valdes som hjälten i publikationen. Vissa av de metoder som beskrivs kan dock vara universella, beroende på din applikationsarkitektur.

Migrationer av relationsstrukturer är ett påtvingat sätt att hantera den svaga flexibiliteten hos relationsdatalagrar. På OOP-modets tidevarv innebar stilen att arbeta med databaser att vi skulle beskriva schemat en gång och inte röra det igen. Men verkligheten är alltid att saker och ting förändras, och ändringar i tabellstrukturen krävs ganska ofta. Naturligtvis kan själva processen vara smärtsam och obehaglig.

Jag kommer inte att gå djupare in på beskrivningen av tekniken och instruktionerna för att lägga till ett bibliotek till ditt projekt; en hel del artiklar har skrivits om detta ämne:

Dessutom fanns det redan en utmärkt artikel om ämnet användbara tips:

Советы

Jag vill dela med mig av mina råd och kommentarer, som föddes genom svett, blod och smärta av att lösa problem med migration.

1. Innan du börjar arbeta bör du bekanta dig med avsnittet om bästa praxis om Online Liquibase

där enkla men mycket viktiga saker beskrivs, utan vilka användning av biblioteket kan komplicera ditt liv. Till exempel kommer ett ostrukturerat tillvägagångssätt för att hantera ändringsuppsättningar förr eller senare att leda till förvirring och trasiga migrationer. Om du inte rullar ut ömsesidigt beroende förändringar av databasstrukturen och tjänstelogiken samtidigt är det stor sannolikhet att detta leder till röda tester eller en trasig miljö. Dessutom innehåller rekommendationer för användning av Liquibase på den officiella webbplatsen en klausul om utveckling och testning av återställningsskript tillsammans med de viktigaste migreringsskripten. Tja, i artikeln https://habr.com/ru/post/178665/ Det finns kodexempel angående migrationer och återställningsmekanismen.

2. Om du börjar använda migreringsverktyg, tillåt inte manuella korrigeringar i databasstrukturen

Som ordspråket säger: "En gång Persil, alltid Persil." Om basen för din applikation börjar hanteras av Liquibase leder eventuella manuella ändringar omedelbart till ett inkonsekvent tillstånd, och nivån av förtroende för ändringsuppsättningar blir noll. Potentiella risker inkluderar flera timmar att återställa databasen, i värsta fall en död server. Om du har en "old school" DBA-arkitekt i ditt team, förklara tålmodigt och eftertänksamt för honom hur illa det kommer att gå om han helt enkelt redigerar databasen enligt sin egen förståelse från en villkorlig SQL-utvecklare.

3. Om ändringsuppsättningen redan har skjutits in i arkivet, undvik att redigera

Om en annan utvecklare gjorde en pull och tillämpade en ändringsuppsättning, som senare kommer att redigeras, kommer han definitivt att minnas dig med ett vänligt ord när han får ett felmeddelande när han startar applikationen. Om redigering av ändringsuppsättningen på något sätt läcker in i utvecklingen, måste du följa den hala backen med snabbkorrigeringar. Kärnan i problemet vilar på valideringen av ändringar med hashsumma - Liquibase huvudmekanism. När du redigerar ändringsuppsättningskoden ändras hashbeloppet. Redigera ändringsuppsättningar är endast möjligt när det är möjligt att distribuera hela databasen från början utan att förlora data. I det här fallet kan omfaktorisering av SQL- eller XML-koden tvärtom göra livet enklare och göra migrering mer läsbar. Ett exempel skulle vara en situation där, i början av applikationen, kom överens om schemat för källdatabasen inom teamet.

4. Ha om möjligt verifierade säkerhetskopior av databas

Här tror jag att allt är klart. Om migreringen plötsligt misslyckades kan allt returneras. Liquibase har ett verktyg för att återställa ändringar, men återställningsskripten är också skrivna av utvecklaren själv, och de kan ha problem med samma sannolikhet som skripten för huvudändringsuppsättningen. Det betyder att det är användbart att spela säkert med säkerhetskopior i alla fall.

5. Använd beprövade säkerhetskopior av databas i utvecklingen, om möjligt

Om detta inte strider mot kontrakt och integritet finns det inga personuppgifter i databasen, och den väger inte så mycket som två solar - innan du använder den på live-migreringsservrar kan du kontrollera hur den kommer att fungera på utvecklarens maskin och beräkna nästan 100 % av potentiella problem under migration.

6. Kommunicera med andra utvecklare i teamet

I en välorganiserad utvecklingsprocess vet alla i teamet vem som gör vad. I verkligheten är detta ofta inte fallet, därför, om du förbereder ändringar i databasstrukturen som en del av din uppgift, är det lämpligt att dessutom meddela hela teamet om detta. Om någon gör ändringar parallellt bör du organisera dig noggrant. Det är värt att kommunicera med kollegor efter avslutat arbete, inte bara i början. Många potentiella problem med ändringsuppsättningar kan lösas vid kodgranskning.

7. Tänk på vad du gör!

Det verkar som självklara råd som gäller i alla situationer. Många problem hade dock kunnat undvikas om utvecklaren ännu en gång hade analyserat vad han gjorde och vad det kunde påverka. Att arbeta med migrering kräver alltid extra uppmärksamhet och noggrannhet.

fällor

Låt oss nu titta på de typiska fällorna som du kan falla i om du inte följer råden ovan, och exakt vad ska du göra?

Situation 1: Två utvecklare försöker lägga till nya ändringar samtidigt

Hur du undviker att skjuta dig själv i foten med Liquibase
Vasya och Petya vill skapa en ändringsuppsättning version 4, utan att känna till varandra. De gjorde ändringar i databasstrukturen och utfärdade en pull-begäran med olika ändringsuppsättningsfiler. Följande verkningsmekanism föreslås:

Hur man bestämmer sig

  1. På något sätt måste kollegor komma överens om i vilken ordning deras ändringar ska gå, till exempel bör Petin tillämpas först.
  2. Någon borde lägga till den andra till sig själv och markera Vasyas ändringsuppsättning med version 5. Detta kan göras genom Cherry Pick eller en snygg sammanfogning.
  3. Efter ändringar bör du definitivt kontrollera giltigheten av de åtgärder som vidtagits.
    Faktum är att Liquibase-mekanismerna tillåter dig att ha två version 4-ändringsuppsättningar i förvaret, så att du kan lämna allt som det är. Det vill säga att du helt enkelt kommer att ha två ändringar av version 4 med olika namn. Med detta tillvägagångssätt blir det senare mycket svårt att navigera i databasversionerna.

Dessutom håller Liquibase, liksom hobitarnas hem, på många hemligheter. En av dem är nyckeln validCheckSum, som dök upp i version 1.7 och låter dig ange ett giltigt hashvärde för en specifik ändringsuppsättning, oavsett vad som lagras i databasen. Dokumentation https://www.liquibase.org/documentation/changeset.html säger följande:

Lägg till en kontrollsumma som anses giltig för denna changeSet, oavsett vad som lagras i databasen. Används främst när du behöver ändra ett changeSet och inte vill att fel ska slängas i databaser som det redan har körts på (inte en rekommenderad procedur)

Ja, ja, denna procedur rekommenderas inte. Men ibland behärskar en stark ljusmagiker också mörka tekniker

Situation 2: Migrering som beror på data

Hur du undviker att skjuta dig själv i foten med Liquibase

Låt oss anta att du inte har möjlighet att använda databassäkerhetskopior från liveservrar. Petya skapade en ändringsuppsättning, testade den lokalt och, med full tillförsikt om att han hade rätt, gjorde en pull-förfrågan till utvecklaren. För säkerhets skull klargjorde projektledaren om Petya hade kontrollerat det och lade sedan till det. Men distributionen på utvecklingsservern föll.

I själva verket är detta möjligt, och ingen är immun mot detta. Detta händer om ändringar i tabellstrukturen på något sätt är knutna till specifika data från databasen. Uppenbarligen, om Petyas databas endast är fylld med testdata, kanske den inte täcker alla problemfall. Till exempel, när man raderar en tabell, visar det sig att det finns poster i andra tabeller av Foreign Key som är relaterade till poster i den som raderas. Eller när man ändrar en kolumntyp visar det sig att inte 100 % av datan kan konverteras till den nya typen.

Hur man bestämmer sig

  • Skriv speciella skript som kommer att användas en gång tillsammans med migreringen och föra data till rätt form. Detta är ett generellt sätt att lösa problemet med att överföra data till nya strukturer efter att ha tillämpat migrering, men något liknande kan tillämpas innan, i speciella fall. Denna väg är naturligtvis inte alltid tillgänglig, eftersom redigering av data på liveservrar kan vara farligt och till och med destruktivt.
  • Ett annat svårt sätt är att redigera en befintlig ändringsuppsättning. Svårigheten är att alla databaser där det redan har tillämpats i sin befintliga form kommer att behöva återställas. Det är mycket möjligt att hela backend-teamet kommer att tvingas att lokalt rulla ut databasen från grunden.
  • Och det mest universella sättet är att överföra problemet med data till utvecklarens miljö, återskapa samma situation och lägga till en ny ändringsuppsättning, till den trasiga, vilket kommer att kringgå problemet.
    Hur du undviker att skjuta dig själv i foten med Liquibase

I allmänhet gäller att ju mer databasen liknar produktionsserverdatabasen till sin sammansättning, desto mindre är chansen att problem med migrering kommer att gå långt. Och, naturligtvis, innan du skickar en ändringsuppsättning till förvaret, bör du tänka flera gånger om det kommer att bryta något.

Situation 3. Liquibase börjar användas efter att den har gått i produktion

Anta att teamledaren bad Petya att inkludera Liquibase i projektet, men projektet är redan i produktion och det finns en befintlig databasstruktur.

Följaktligen är problemet att på alla nya servrar eller utvecklarmaskiner måste dessa tabeller återskapas från början, och den befintliga miljön måste förbli i ett konsekvent tillstånd, redo att acceptera nya ändringar.

Hur man bestämmer sig

Det finns också flera sätt:

  • Det första och mest uppenbara är att ha ett separat skript som måste appliceras manuellt vid initialisering av en ny miljö.
  • Det andra är mindre uppenbart, ha en Liquibase-migrering som är i en annan Liquibase-kontext och tillämpa den. Du kan läsa mer om Liquibase Context här: https://www.liquibase.org/documentation/contexts.html. Generellt sett är detta en intressant mekanism som framgångsrikt kan användas till exempel för testning.
  • Den tredje vägen består av flera steg. Först måste en migrering skapas för befintliga tabeller. Då måste den appliceras på någon miljö och därmed erhålls dess hashsumma. Nästa steg är att initiera tomma Liquibase-tabeller på vår icke-tomma server, och i tabellen med historik över användningen av ändringsuppsättningar kan du manuellt lägga in en post om ändringsuppsättningen "som om den tillämpas" med ändringar som redan finns i databasen . Således, på en befintlig server, kommer historiknedräkningen att börja från version 2, och alla nya miljöer kommer att bete sig identiskt.
    Hur du undviker att skjuta dig själv i foten med Liquibase

Situation 4. Migrationer blir enorma och har inte tid att slutföra

I början av tjänsteutvecklingen används som regel Liquibase som ett externt beroende, och alla migreringar bearbetas när applikationen startar. Men med tiden kan du stöta på följande fall:

  • Migrationerna blir enorma och tar lång tid att genomföra.
  • Det finns ett behov av migrering i distribuerade miljöer, till exempel på flera databasserverinstanser samtidigt.
    I det här fallet kommer omvandlingar för länge att resultera i en timeout när programmet startar. Att tillämpa migrering på varje applikationsinstans separat kan dessutom leda till att olika servrar inte är synkroniserade.

Hur man bestämmer sig

I sådana fall är ditt projekt redan stort, kanske till och med en vuxen, och Liquibase börjar fungera som ett separat externt verktyg. Faktum är att Liquibase som bibliotek är kompilerad till en jar-fil, och kan fungera som ett beroende inom ett projekt eller självständigt.

I fristående läge kan du överlåta implementeringen av migrering till din CI/CD-miljö eller till dina systemadministratörer och distributionsspecialisters starka axlar. För att göra detta behöver du kommandoraden Liquibase https://www.liquibase.org/documentation/command_line.html. I det här läget blir det möjligt att starta programmet efter att alla nödvändiga migreringar har utförts.

Utgång

Faktum är att det kan finnas många fler fallgropar när man arbetar med databasmigreringar, och många av dem kräver ett kreativt tillvägagångssätt. Det är viktigt att förstå att om du använder verktyget på rätt sätt kan de flesta av dessa fallgropar undvikas. Specifikt var jag tvungen att hantera alla de listade problemen i olika former, och några av dem var resultatet av mina misstag. Oftast sker detta, naturligtvis, på grund av ouppmärksamhet, men ibland på grund av kriminell oförmåga att använda verktyget.

Källa: will.com

Lägg en kommentar