View
80
Download
0
Category
Preview:
Citation preview
Liquibase w praktyce
Mateusz Lubański
JUG Bielsko-Biała
1 września 2016
Mateusz Lubański Liquibase w praktyce 1 września 2016 1 / 30
O mnie
Java Developer 5+Technologie backendoweObecnie pracuje w Omnetric
Fan Agile i ScrumHobby: narty/kajaki/trekking//salsa
http://linkedin.com/in/mateuszlubanski
Mateusz Lubański Liquibase w praktyce 1 września 2016 2 / 30
Podstawowe problemy w zarządzaniu bazą
śledzenie zmian
dane słownikowe
dane testowe
automatyzacja
wersjonowanie
niezależny od środowiska
łatwy
Mateusz Lubański Liquibase w praktyce 1 września 2016 3 / 30
Istniejące rozwiązania
Liquibase
złożony
xml, yaml, json, sql<databaseChangeLog>
<changeSet id=”1” author=”mlubanski”><sqlFile path=”V1.sql” />
</changeSet><changeSet id=”2” author=”mlubanski”>
<sqlFile path=”V2.sql” /></changeSet>
<databaseChangeLog>
Flyway
prosty
sqlV1.sqlV2.sqlV3.sql
Mateusz Lubański Liquibase w praktyce 1 września 2016 4 / 30
Integracja
Command Line
Maven
Spring-Boot
Mateusz Lubański Liquibase w praktyce 1 września 2016 5 / 30
Command Line Integration
full commandjava −jar ./liquibase−core−3.5.1.jar \−−driver=org.postgresql.Driver \−−classpath=./postgresql−9.2−1002−jdbc4.jar \−−changeLogFile=src/main/resources/db/changelog/db.changelog−master.xml \−−url=”jdbc:postgresql://localhost:5432/sampledb” \−−username=sample \−−password=topsecret \update
using liquibase.propertiesdriver: org.postgresql.Driverclasspath: ./postgresql−9.2−1002−jdbc4.jarurl: jdbc:postgresql://localhost:5432/sampledbusername: samplepassword: topsecret
java −jar ./liquibase−core−3.5.1.jar \−−changeLogFile=src/main/resources/db/changelog/db.changelog−master.xml \update
Mateusz Lubański Liquibase w praktyce 1 września 2016 6 / 30
Maven Integration
dependency<dependency>
<groupId>org.liquibase</groupId><artifactId>liquibase−core</artifactId><version>3.5.1</version>
</dependency>
plugin<plugin>
<groupId>org.liquibase</groupId><artifactId>liquibase−maven−plugin</artifactId><version>3.5.1</version><configuration>
<propertyFile>src/main/resources/liquibase/liquibase.properties</propertyFile><changeLogFile>src/main/resources/db/changelog/db.changelog−master.xml</changeLogFile>
</configuration><executions>
<execution><goals>
<goal>update</goal></goals>
</execution></executions>
</plugin>
commandmvn liquibase:update
Mateusz Lubański Liquibase w praktyce 1 września 2016 7 / 30
Spring-Boot Integration
dependency<dependency>
<groupId>org.liquibase</groupId><artifactId>liquibase−core</artifactId>
</dependency>
plugin<plugin>
<groupId>org.springframework.boot</groupId><artifactId>spring−boot−maven−plugin</artifactId>
</plugin>
application.propertiesliquibase.enabled=trueliquibase.change−log=classpath:/db/changelog/db.changelog−master.xml
spring.datasource.url=jdbc:postgresql://localhost:5432/sampledbspring.datasource.username=samplespring.datasource.password=secret
commandmvn spring−boot:run
Mateusz Lubański Liquibase w praktyce 1 września 2016 8 / 30
Struktura xml
databaseChangeLog
preConditions
property
changeSet
include
changeSet
comment
preConditions
Any Refactoring Tag(s)
rollback
Mateusz Lubański Liquibase w praktyce 1 września 2016 9 / 30
Pierwszy changeSet
sql<changeSet id=”1” author=”mlubanski”>
<sqlFile relativeToChangelogFile=”true” path=”sql/create person.sql”/></changeSet>
CREATE TABLE person(
id serial NOT NULL,name character varying(100) NOT NULL,date date DEFAULT now(),CONSTRAINT pk person PRIMARY KEY (id),CONSTRAINT person name key UNIQUE (name)
);
xml<changeSet id=”2” author=”mlubanski”>
<createTable tableName=”USER”><column name=”ID” type=”int” autoIncrement=”true” >
<constraints primaryKey=”true” nullable=”false” /></column><column name=”NAME” type=”varchar(100)” >
<constraints nullable=”false” unique=”true”/></column><column name=”DATE” type=”date” defaultValueComputed=”now()”>
<constraints nullable=”false” /></column>
</createTable></changeSet>
Mateusz Lubański Liquibase w praktyce 1 września 2016 10 / 30
Skąd Liquibase wie który skrypt został już wykonany?
id musi być unikalne dla changeLog’a i użytkownika
Liquibase generuje i zapisuje md5sum dla każdego wykonanegochangeSet’a
Główna idea liquibase’a to ciągła liniowa sekwencja zmian na baziedanych. Podobnie jak przy Versioning Control System niemodyfikujemy starych commit’ów tak przy liquibas’e niemodyfikujemy starych changeSet’ów ponieważ możemy zerwaćspójność bazy danych.
Mateusz Lubański Liquibase w praktyce 1 września 2016 11 / 30
Skąd Liquibase wie który skrypt został już wykonany?
DATABASECHANGELOGLOCK (liquibase releaseLocks)
LOCKED
LOCKGRANTED
LOCKEDBY
DATABASECHANGELOG
ID
AUTHOR
FILENAME
DATEEXECUTED
EXECTYPE [EXECUTED, FAILED, SKIPPED, RERAN, MARKRAN]
MD5SUM
DESCRIPTION
Mateusz Lubański Liquibase w praktyce 1 września 2016 12 / 30
Wspierane Refactorings
create: table, view, procedure, sequence, index
add: column, foreign key, not null, unique, default value, primary key,autoincrement
drop: ...
rename: column, table, view,
others: insert, load data, sql, sqlFile, modify data type, update
Mateusz Lubański Liquibase w praktyce 1 września 2016 13 / 30
Wspierane bazy danych
MySQL
PostgreSQL
Oracle
Sql Server
Sybase
DB2
Apache Derby
HSQL
H2
Informmix
Firebird
SQLite
Mateusz Lubański Liquibase w praktyce 1 września 2016 14 / 30
Wykonywanie tego samego changeSet wielokrotnie
<databaseChangeLog><changeSet id=”3” author=”mlubanski” runOnChange=”true”>
<sqlFile path=”deactivate user procedure.sql” splitStatements=”false” /><rollback>DROP PROCEDURE DEACTIVATE USER;</rollback>
</changeSet>
<changeSet id=”4” author=”mlubanski” runAlways=”true” ><sqlFile path=”clean deactivated users.sql” splitStatements=”false” />
</changeSet><databaseChangeLog>
Mateusz Lubański Liquibase w praktyce 1 września 2016 15 / 30
Wprowadzanie danych
changelog.xml<changeSet author=”mlubanski” id=”5” runOnChange=”true”>
<loadData tableName=”COUNTRY” file=”data/countries.csv” ><column name=”name” type=”STRING” /><column name=”sequence” type=”NUMERIC” />
</loadData><rollback>
DELETE FROM COUNTRY;</rollback>
</changeSet>
countries.csvname,sequencePolska,1Austria,2Niemcy,3Anglia,4
Mateusz Lubański Liquibase w praktyce 1 września 2016 16 / 30
Context
changelog.xml<changeSet author=”mlubanski” id=”5” runOnChange=”true” context=”dev”>...</changeSet>
Spring-Boot application.propertiesliquibase.contexts=dev
Maven plugin<plugin>
<groupId>org.liquibase</groupId><artifactId>liquibase−maven−plugin</artifactId>
<configuration><contexts>dev</contexts>...
</configuration></plugin>
Command Linejava −jar ./liquibase−core−3.5.1.jar \−−changeLogFile=src/main/resources/db/changelog/db.changelog−master.xml \−−contexts=dev \update
Mateusz Lubański Liquibase w praktyce 1 września 2016 17 / 30
Preconditions
Warunki zadeklarowane na poziomie changeLog mają globalny zakres dowszystkich changeSet’ów<preConditions>
<or><dbms type=”h2” /><dbms type=”mysql” />
</or></preConditions>
<changeSet id=”6” author=”mlubanski”><preConditions onFail=”WARN”>
<sqlCheck expectedResult=”0”>select count(∗) from oldtable</sqlCheck></preConditions><dropTable tableName=”oldtable”/>
</changeSet>
onFail: HALT, CONTINUE, MARK RAN, WARN<changeSet id=”7” author=”mlubanski” dbms=”postgresql”>
<sqlFile path=”insert.sql” /></changeSet>
Mateusz Lubański Liquibase w praktyce 1 września 2016 18 / 30
Preconditions
Dostępne warunki:
dbms
changeSetExecuted
columnExists, tableExists, viewExists, foreignKeyConstraintExists,sequenceExists, primaryKeyExists
sqlCheck
changeLogPropertyDefined
customPrecondition
Mateusz Lubański Liquibase w praktyce 1 września 2016 19 / 30
Property and Include
Property:<property name=”key.type” value=”NUMERIC(10,0)” /><property name=”name.type” value=”VARCHAR(255)”/><property name=”text.type” value=”VARCHAR(2000)” /><property name=”now” value=”SYSDATE ” dbms=”oracle” /><property name=”now” value=”NOW()” dbms=”postgresql” />
<changeSet id=”8” author=”mlubanski”><createTable tableName=”MESSAGE”>
<column name=”ID” type=”${key.type}” autoIncrement=”true”><constraints primaryKey=”true” nullable=”false” />
</column><column name=”TITLE” type=”${name.type}”>
<constraints nullable=”false” /></column><column name=”CONTENT” type=”${text.type}” /><column name=”DATE” type=”date” defaultValueComputed=”${now}”>
<constraints nullable=”false” /></column>
</createTable></changeSet>
Include:<include file=”R1/db.changelog−master.xml” relativeToChangelogFile=”true” /><include file=”dev/sample−data.changelog.xml” relativeToChangelogFile=”true” context=”dev” />
Mateusz Lubański Liquibase w praktyce 1 września 2016 20 / 30
Przykładowa struktura
dbchangelogdb.changelog.dev.xmldb.changelog.production.xmlR1datadictionary.csv
db.changelog.2016-08.20.xmldb.changelog.2016-08.21.xmldb.changelog.master.xml
R2datadictionary.csv
db.changelog.2016-08.20.xmldb.changelog.2016-08.21.xmldb.changelog.master.xml
Mateusz Lubański Liquibase w praktyce 1 września 2016 21 / 30
Przykładowa struktura
db\changelog\db.changelog.dev.xml<property name=”key.type” value=”NUMERIC(10,0)” /><property name=”name.type” value=”VARCHAR(255)”/>...
<include file=”R1/db.changelog.master.xml” relativeToChangelogFile=”true” /><include file=”R2/db.changelog.master.xml” relativeToChangelogFile=”true” />
db\changelog\R1\db.changelog.master.xml<include file=”db.changelog.2016−08.20.xml” relativeToChangelogFile=”true” /><include file=”db.changelog.2016−08.20.xml” relativeToChangelogFile=”true” />
Mateusz Lubański Liquibase w praktyce 1 września 2016 22 / 30
Jak wdrożyć liquibase do istniejącego projektu
1 Generujemy changeLog’a (komenda ta nie eksportuje: Storedprocedures, functions, packages, Triggers)java −jar ./liquibase−core−3.5.1.jar \db.changelog.xml \generateChangeLog
2 Odpalamy changelogSync który wypełnia nam tabelęDATABASECHANGELOG wpisami z changeSet’ów bez wykonywaniaich na baziejava −jar ./liquibase−core−3.5.1.jar \db.changelog.xml \changeLogSync
Mateusz Lubański Liquibase w praktyce 1 września 2016 23 / 30
Przydatne triki
Co gdy admin na powie, że on musi mieć SQL’a? :)java −jar ./liquibase−core−3.5.1.jar \src/main/resources/db/changelog/db.changelog−master.xml \updateSQL > /tmp/script.sql
Czy na pewno baza A jest taka sama jak baza B?java −jar ./liquibase−core−3.5.1.jar \diffChangeLog−−referenceUrl=”jdbc:postgresql://localhost:5432/B” \−−referenceUsername=sample \−−referencePassword=topsecret \> diff.database.changelog.xml
Diff Nie wspiera: Non-foreign key constraints (check, etc), StoredProcedures, Data type length
Mateusz Lubański Liquibase w praktyce 1 września 2016 24 / 30
Warto wspomnieć?
dbDocCurrent TablesAuthorsChange LogsPending ChangesPending SQLMost Recent Changes
RollbackLiczbaDataTag
Mateusz Lubański Liquibase w praktyce 1 września 2016 25 / 30
Podsumowanie
śledzenie zmian - spersonalizowane changeSet’y zapisywane w baziewraz z dbDoc
dane słownikowe - loadData + .csv
dane testowe - contexts
automatyzacja - libuibase:update
wersjonowanie - include + odpowiednia struktura
niezależny od środowiska - xml
łatwy - umiarkowanie łatwy z wielkimi możliwościami
Mateusz Lubański Liquibase w praktyce 1 września 2016 26 / 30
Demo Time :)
Mateusz Lubański Liquibase w praktyce 1 września 2016 27 / 30
Pytania?
Mateusz Lubański Liquibase w praktyce 1 września 2016 28 / 30
Dziękuję za uwagę :)
Mateusz Lubański Liquibase w praktyce 1 września 2016 29 / 30
Przydatne linki
http://www.liquibase.org/documentation/index.html
http://www.liquibase.org/documentation/changes/
http://projects.spring.io/spring-boot/
http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
http://www.slideshare.net/MateuszLubaski/liquibase-w-praktyce
https://github.com/mlubanski/questionnarie-server
Mateusz Lubański Liquibase w praktyce 1 września 2016 30 / 30
Recommended