Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
LiquiBase vs Flyway
Baltic DevOps
Andrei Solntsev
12.05.2015
Tallinn
Agile
Change -
itshould be
easy
Database
Change is complex
● Tables
● Live data!
Database
Change is complex
● Tables
● Live data!
● Stored procedures
● Pl/Sql packages
● Materialized views
● Triggers
● D...
Life BEFORE liquibase
CREATE TABLE PERSON (
first_name VARCHAR2(16),
last_name VARCHAR2(16)
);
CREATE TABLE PERSON (
first_name VARCHAR2(16),
middle_name VARCHAR2(2),
last_name VARCHAR2(16)
);
Life BEFORE liquibase
CREATE TABLE PERSON (
first_name VARCHAR2(32),
middle_name VARCHAR2(32),
last_name VARCHAR2(32)
);
Life BEFORE liquibase
Solution:
small steps
1.sql CREATE TABLE PERSON
(first_name, last_name)
2.sql ALTER TABLE PERSON
ADD COLUMN middle_name
3....
Tools
● Flyway DB - simple
● - powerful
DBDeploy
Flyway: just files
V1__blah.sql
V2_blah.sql
V3_blah.sql
<sqlFile path="1.sql"/>
<sqlFile path="2.sql"/>
<sqlFile path="3.sql"/>
LiquiBase: XML
changelog.xml
<changeSet id="1">
<sqlFile path="1.sql"/>
</changeSet>
<changeSet id="2">
<sqlFile path="2.sql"/>
</changeSet>
<changeSet...
<changeSet id="1">
<sqlFile path="1.sql"/>
</changeSet>
<changeSet id="2" runAlways="true">
<sqlFile path="2.sql"/>
</chan...
<changeSet id="1">
<sqlFile path="1.sql"/>
</changeSet>
<changeSet id="2" runAlways="true">
<sqlFile path="2.sql"/>
</chan...
LiquiBase: XML
<changeSet id="4" dbms="oracle">
<sqlFile path="5.sql"/>
</changeSet>
<changeSet id="5" context="test">
<sq...
<changeSet id="1" author="andrei">
<createTable tableName="person">
<column name="id" type="int" autoIncrement="true"/>
<c...
DEMO
https://github.com/asolntsev/liquibase-ee
<changeSet id="1" author="andrei">
<createTable tableName="person">
<column name="id" type="int" autoIncrement="true"/>
<c...
LiquiBase refactorings
<changeSet>
<renameColumn
tableName="order_comment"
oldColumnName="author_id"
newColumnName="employ...
LiquiBase refactorings
<modifyDataType
tableName="customer"
columnName="middle_name"
newDataType="VARCHAR2(100)"
/>
Data loading
<changeSet runOnChange="true">
<loadData tableName="CLIENT" file="clt.csv">
<column header="id"
name="ENTITYI...
Why
it's
needed?
Oppa Agile style
● Local development
○ Oracle XE (dev servers must die!)
● Easy run
○ ant start
● In-memory DB for tests/d...
3 DBs
1. Oracle - in production
2. Oracle XE - in development
3. H2 in-memory
- for demo
- for tests
- for designer
DB configuration in GIT
conf/
dev.properties
db.url=jdbc:oracle:thin:@server1:1521:devdb
local.properties
db.url=jdbc:orac...
Run
● ant
● ant -Denv=dev
● ant -Denv=live
● ant start - runs demo
Opposition
Admins: we wanna see SQL!
SQL men: it works only for Java
CVS men: we already have scripts
SQL preview
ant show-sql
LiquiBase
generates,
but
does not run SQL
Admins are satisfied
Procedures
<changeSet runOnChange="true" dbms="oracle">
<sqlFile
path="procedures/log_message.sql"
splitStatements="false"...
Simple DB refactorings
My favorite - having
“CREATE OR REPLACE”:
● Procedures
● Functions
● Pl/Sql
● VIEWs
● Triggers
<cha...
Nontrivial refactorings
Those without
CREATE OR REPLACE
Materialized view
<changeSet id="002">
<sql>
CREATE MATERIALIZED VIEW currency_mv ...
</sql>
</changeSet>
Materialized view
<changeSet id="001" failOnError="false">
<sql>
DROP MATERIALIZED VIEW currency_mv;
</sql>
</changeSet>
<...
We are happy
● It's easy to develop DB
● It's easy to develop DB
● Jenkins tests DB scripts
We are happy
● It's easy to develop DB
● Jenkins tests DB scripts
● Designer edits HTML
We are happy
● It's easy to develop DB
● Jenkins tests DB scripts
● Designer edits HTML
● Admin sleeps at night
We are happy
● It's easy to develop DB
● Jenkins tests DB scripts
● Designer edits HTML
● Admin sleeps at night
● UI-tests run on local...
To read
commit & push
Andrei Solntsev
andrei.solntsev@gmail.com
@asolntsev
Behind the scenes
changelog.xml
releases
<databaseChangeLog>
<include file="changelog_001.xml"/>
<include file="changelog_002.xml"/>
<includ...
Raw SQL
<changeSet id="201308181029">
<sql>
CREATE TABLE payment (
id NUMBER NOT NULL,
description VARCHAR2(100 CHAR),
url...
Constraints
<changeSet>
<addColumn tableName="payment">
<column name="customer_id" type="NUMBER"/>
</addColumn>
<addForeig...
Some DB-specific
(e.g. Oracle)
<changeSet dbms="oracle">
<createSequence
sequenceName="order_file_id_seq"/>
</changeSet>
Materialized view
<changeSet dbms="oracle">
<sql>
CREATE MATERIALIZED VIEW currency_mv
REFRESH COMPLETE
as select * from (...
Refresh Mat View
<changeSet dbms="oracle">
<sqlFile path="mviews/refresh_mv.sql"/>
<rollback><sql>
BEGIN
dbms_refresh.dest...
Refresh Mat View
<changeSet dbms="oracle">
<sqlFile path="mviews/refresh_mv.sql"/>
<rollback><sql>
BEGIN
dbms_refresh.dest...
LiquiNinja
How to re-run changesets:
<changeSet id="115">
<sql>
update databasechangelog
setfilename = 'db/static_data_001...
commit & push
Andrei Solntsev
andrei.solntsev@gmail.com
@asolntsev
Upcoming SlideShare
Loading in …5
×

Liquibase & Flyway @ Baltic DevOps

16,471 views

Published on

Automated database updates (with LiquiBase and FlyWay)

"Baltic DevOps" conference.
Tallinn, Estonia. 12.05.2015

Published in: Software

Liquibase & Flyway @ Baltic DevOps

  1. 1. LiquiBase vs Flyway Baltic DevOps Andrei Solntsev 12.05.2015 Tallinn
  2. 2. Agile Change - itshould be easy
  3. 3. Database Change is complex ● Tables ● Live data!
  4. 4. Database Change is complex ● Tables ● Live data! ● Stored procedures ● Pl/Sql packages ● Materialized views ● Triggers ● DB Links
  5. 5. Life BEFORE liquibase CREATE TABLE PERSON ( first_name VARCHAR2(16), last_name VARCHAR2(16) );
  6. 6. CREATE TABLE PERSON ( first_name VARCHAR2(16), middle_name VARCHAR2(2), last_name VARCHAR2(16) ); Life BEFORE liquibase
  7. 7. CREATE TABLE PERSON ( first_name VARCHAR2(32), middle_name VARCHAR2(32), last_name VARCHAR2(32) ); Life BEFORE liquibase
  8. 8. Solution: small steps 1.sql CREATE TABLE PERSON (first_name, last_name) 2.sql ALTER TABLE PERSON ADD COLUMN middle_name 3.sql ALTER TABLE PERSON DROP COLUMN middle_name That's
  9. 9. Tools ● Flyway DB - simple ● - powerful DBDeploy
  10. 10. Flyway: just files V1__blah.sql V2_blah.sql V3_blah.sql
  11. 11. <sqlFile path="1.sql"/> <sqlFile path="2.sql"/> <sqlFile path="3.sql"/> LiquiBase: XML changelog.xml
  12. 12. <changeSet id="1"> <sqlFile path="1.sql"/> </changeSet> <changeSet id="2"> <sqlFile path="2.sql"/> </changeSet> <changeSet id="3"> <sqlFile path="3.sql"/> </changeSet> LiquiBase: XML
  13. 13. <changeSet id="1"> <sqlFile path="1.sql"/> </changeSet> <changeSet id="2" runAlways="true"> <sqlFile path="2.sql"/> </changeSet> <changeSet id="3"> <sqlFile path="3.sql"/> </changeSet> LiquiBase: XML
  14. 14. <changeSet id="1"> <sqlFile path="1.sql"/> </changeSet> <changeSet id="2" runAlways="true"> <sqlFile path="2.sql"/> </changeSet> <changeSet id="3"runOnChange="true"> <sqlFile path="3.sql"/> </changeSet> LiquiBase: XML
  15. 15. LiquiBase: XML <changeSet id="4" dbms="oracle"> <sqlFile path="5.sql"/> </changeSet> <changeSet id="5" context="test"> <sqlFile path="5.sql"/> </changeSet> <changeSet id="6" failOnError="false"> <sqlFile path="6.sql"/> </changeSet>
  16. 16. <changeSet id="1" author="andrei"> <createTable tableName="person"> <column name="id" type="int" autoIncrement="true"/> <column name="firstname" type="varchar(50)"/> <column name="lastname" type="varchar(50)"/> </createTable> </changeSet> LiquiBase DSL
  17. 17. DEMO https://github.com/asolntsev/liquibase-ee
  18. 18. <changeSet id="1" author="andrei"> <createTable tableName="person"> <column name="id" type="int" autoIncrement="true"/> <column name="firstname" type="varchar(50)"/> <column name="lastname" type="varchar(50)"/> </createTable> </changeSet> LiquiBase DSL ● Supports all Dbs ● IDE autocompletion ● Rollback out-of-the-box ● Built-in refactorings
  19. 19. LiquiBase refactorings <changeSet> <renameColumn tableName="order_comment" oldColumnName="author_id" newColumnName="employee_id" /> </changeSet>
  20. 20. LiquiBase refactorings <modifyDataType tableName="customer" columnName="middle_name" newDataType="VARCHAR2(100)" />
  21. 21. Data loading <changeSet runOnChange="true"> <loadData tableName="CLIENT" file="clt.csv"> <column header="id" name="ENTITYID"/> <column header="DESCRIPTION" name="DESCRIPTION"/> </loadData> </changeSet>
  22. 22. Why it's needed?
  23. 23. Oppa Agile style ● Local development ○ Oracle XE (dev servers must die!) ● Easy run ○ ant start ● In-memory DB for tests/demo ○ ant test
  24. 24. 3 DBs 1. Oracle - in production 2. Oracle XE - in development 3. H2 in-memory - for demo - for tests - for designer
  25. 25. DB configuration in GIT conf/ dev.properties db.url=jdbc:oracle:thin:@server1:1521:devdb local.properties db.url=jdbc:oracle:thin:@127.0.0.1:1521:xe inmemory.properties db.url=jdbc:h2:out/liquibase-ee
  26. 26. Run ● ant ● ant -Denv=dev ● ant -Denv=live ● ant start - runs demo
  27. 27. Opposition Admins: we wanna see SQL! SQL men: it works only for Java CVS men: we already have scripts
  28. 28. SQL preview ant show-sql LiquiBase generates, but does not run SQL Admins are satisfied
  29. 29. Procedures <changeSet runOnChange="true" dbms="oracle"> <sqlFile path="procedures/log_message.sql" splitStatements="false"/> <rollback> DROP procedure log_message </rollback> </changeSet>
  30. 30. Simple DB refactorings My favorite - having “CREATE OR REPLACE”: ● Procedures ● Functions ● Pl/Sql ● VIEWs ● Triggers <changeSet runOnChange="true"> <sqlFile path="another.sql"/> </changeSet>
  31. 31. Nontrivial refactorings Those without CREATE OR REPLACE
  32. 32. Materialized view <changeSet id="002"> <sql> CREATE MATERIALIZED VIEW currency_mv ... </sql> </changeSet>
  33. 33. Materialized view <changeSet id="001" failOnError="false"> <sql> DROP MATERIALIZED VIEW currency_mv; </sql> </changeSet> <changeSet id="002"> <sql> CREATE MATERIALIZED VIEW currency_mv ... </sql> </changeSet>
  34. 34. We are happy ● It's easy to develop DB
  35. 35. ● It's easy to develop DB ● Jenkins tests DB scripts We are happy
  36. 36. ● It's easy to develop DB ● Jenkins tests DB scripts ● Designer edits HTML We are happy
  37. 37. ● It's easy to develop DB ● Jenkins tests DB scripts ● Designer edits HTML ● Admin sleeps at night We are happy
  38. 38. ● It's easy to develop DB ● Jenkins tests DB scripts ● Designer edits HTML ● Admin sleeps at night ● UI-tests run on localhost We are happy
  39. 39. To read
  40. 40. commit & push Andrei Solntsev andrei.solntsev@gmail.com @asolntsev
  41. 41. Behind the scenes
  42. 42. changelog.xml releases <databaseChangeLog> <include file="changelog_001.xml"/> <include file="changelog_002.xml"/> <include file="changelog_003.xml"/> </databaseChangeLog>
  43. 43. Raw SQL <changeSet id="201308181029"> <sql> CREATE TABLE payment ( id NUMBER NOT NULL, description VARCHAR2(100 CHAR), url VARCHAR2(500 CHAR), upd_dttm TIMESTAMP) </sql> <rollback> DROP TABLE payment </rollback> </changeSet>
  44. 44. Constraints <changeSet> <addColumn tableName="payment"> <column name="customer_id" type="NUMBER"/> </addColumn> <addForeignKeyConstraint baseTableName="payment" baseColumnNames="customer_id" constraintName="payment_customer_fk" referencedTableName="customer" referencedColumnNames="id"/> </changeSet>
  45. 45. Some DB-specific (e.g. Oracle) <changeSet dbms="oracle"> <createSequence sequenceName="order_file_id_seq"/> </changeSet>
  46. 46. Materialized view <changeSet dbms="oracle"> <sql> CREATE MATERIALIZED VIEW currency_mv REFRESH COMPLETE as select * from (select * from currency_xa_pos2@${db.dblink.core}) </sql> <rollback> DROP MATERIALIZED VIEW currency_mv; </rollback> </changeSet>
  47. 47. Refresh Mat View <changeSet dbms="oracle"> <sqlFile path="mviews/refresh_mv.sql"/> <rollback><sql> BEGIN dbms_refresh.destroy('CUR_GRP'); END; </sql></rollback> </changeSet>
  48. 48. Refresh Mat View <changeSet dbms="oracle"> <sqlFile path="mviews/refresh_mv.sql"/> <rollback><sql> BEGIN dbms_refresh.destroy('CUR_GRP'); END; </sql></rollback> </changeSet>
  49. 49. LiquiNinja How to re-run changesets: <changeSet id="115"> <sql> update databasechangelog setfilename = 'db/static_data_001.xml', md5sum = null where id = '201309261214' </sql> </changeSet>
  50. 50. commit & push Andrei Solntsev andrei.solntsev@gmail.com @asolntsev

×