Недавно я начал использовать Liquibase в проекте для отслеживания изменений базы данных в нашем приложении Java Enterprise. Я должен сказать, что мне нравится, как это работает. Это делает развертывание моего приложения (или его нового выпуска) в другой среде более простым и (более) надежным. В прошлом мне приходилось предоставлять сценарий базы данных для администратора баз данных, который должен был выполняться сразу после или до того, как я повторно развернул свой файл EAR / WAR со всеми проблемами, которые идут с этой процедурой (сбой сценария / недоступность DBA и т. Д.). Сейчас я не буду говорить, что с этим решением не может быть проблем, но с точки зрения разработчика оно облегчает жизнь.
Вот как это работает для простого проекта Maven с некоторыми веб-сервисами, которые поддерживаются базой данных MySQL . Поскольку я развернул веб-службы в файле WAR на JBoss, я решил, что сценарии Liquibase запускаются экземпляром ServletContextListener . Чтобы иметь возможность протестировать скрипт базы данных без необходимости развертывания приложения, я также встроил плагин Maven для Liquibase в свой файл pom. Таким образом, я могу запускать сценарии liquibase вручную с Maven для моей локальной базы данных разработки.
Сначала добавьте необходимые зависимости в Maven pom.xml:
<dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> <version>2.0.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.15</version> <scope>provided</scope> </dependency>
Зависимость MySQL необходима только для возможности запуска сценариев Liquibase с Maven. Само приложение использует источник данных, который управляется контейнером, в данном случае JBoss.
Чтобы иметь возможность запускать сценарии Liquibase с Maven, я определил плагин так:
<plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>2.0.1</version> <configuration> <changeLogFile>db.changelogs/my-changelog-master.xml</changeLogFile> <driver>com.mysql.jdbc.Driver</driver> <url>jdbc:mysql://localhost:3306/MyDB</url> <username>admin-user</username> <password>*****</password> </configuration> <executions> <execution> <goals> <goal>update</goal> </goals> </execution> </executions> </plugin>
Как я уже сказал, я выполняю сценарии, вызывая Liquibase с помощью Servlet Listener. Для этого добавьте следующие элементы в файл «web.xml» внутри файла WAR:
... <context-param> <param-name>liquibase.changelog</param-name> <param-value>db.changelogs/db.changelog-master.xml</param-value> </context-param> <context-param> <param-name>liquibase.datasource</param-name> <param-value>java:jboss/datasources/LiquibaseDS</param-value> </context-param> <listener> <listener-class>liquibase.integration.servlet.LiquibaseServletListener</listener-class> </listener> ...
Здесь мы видим, что я определил два параметра:
- liquibase.changelog
- liquibase.datasource
Этот параметр относится к местоположению classpath главного файла db.changelogs. Важно отметить, что этот путь совпадает с тем, который используется в плагине Maven, если вы работаете с той же базой данных. Посмотрите эту проблему, с которой я столкнулся при использовании разных путей.
Это относится к JNDI-имени источника данных, который будет использоваться со сценарием Liquibase. Поскольку этому пользователю базы данных необходимы права на создание объектов базы данных, таких как таблицы, я предлагаю создать отдельный источник данных для использования с приложением. Этот источник данных должен затем соединиться с пользователем, который имеет права только на доступ к данным и не может создавать или удалять объекты.
Последняя часть — это создание файлов db.changelogs. Как рекомендуется здесь, в качестве лучшей практики я обращаюсь к «основному» файлу изменений в конфигурации. В этом главном файле журнала изменений я имею в виду отдельные сценарии. Например, у меня в папке «resources» есть следующий «главный» скрипт:
<?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd"> <include file="db.changelog-1.0.xml" relativeToChangelogFile="true" /> <include file="db.changelog-2.0.xml" relativeToChangelogFile="true" /> </databaseChangeLog>
В сценарии ‘db.changelog-1.0.xml’ я создаю несколько таблиц с набором изменений на основе XML:
<?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd"> <changeSet id="1" author="pascalalma"> <createTable tableName="TEST_TABLE"> <column name="ID" type="bigint(20)" autoIncrement="true"> <constraints primaryKey="true" nullable="false"/> </column> <column name="CODE" type="varchar(20)"> <constraints nullable="false" unique="true"/> </column> <column name="DESCRIPTION" type="varchar(200)"/> <column name="VALUE" type="varchar(200)"/> </createTable> <addUniqueConstraint columnNames="CODE,DESCRIPTION" constraintName="CODE_UK" tableName="TEST_TABLE"/> <createTable tableName="ANOTHER_TEST_TABLE"> <column name="ID" type="bigint(20)" autoIncrement="true"> <constraints primaryKey="true" nullable="false"/> </column> <column name="CODE" type="varchar(20)"> <constraints nullable="false" unique="true"/> </column> <column name="TEST_CODE" type="bigint(20)"> </column> </createTable> <addForeignKeyConstraint baseColumnNames="TEST_CODE" baseTableName="ANOTHER_TEST_TABLE" constraintName="TEST_OTHER_FK" referencedColumnNames="CODE" referencedTableName="TEST_TABLE"/> </changeSet> </databaseChangeLog>
В этом примере сценария я показываю, как создавать таблицы с уникальными ограничениями на комбинации столбцов и как добавлять к ним внешние ключи.
В ‘db.changelog-2.0.xml’ я показываю, как загрузить данные в созданные таблицы, используя в качестве входных данных файл CSV:
<?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd"> <changeSet id="2" author="pascalalma"> <loadData file="db.changelogs/mydata.csv" schemaName="MyDB" quotchar="'" tableName="TEST_TABLE"/> </changeSet> </databaseChangeLog>
В «mydata.csv» я определяю строки для загрузки в таблицу:
CODE,DESCRIPTION,VALUE 'T01','Not specified','FOO' 'T02','Wrongly specified','BAR' 'T03','Correct','FOO-BAR'
В первой строке CSV-файла указаны столбцы в порядке, в котором поля определены в других строках. Это очень удобный способ загрузки исходных данных в таблицы базы данных.
Когда все это на месте, вы можете запустить Liquibase из Maven. Сначала создайте проект с помощью mvn clean install, а затем введите mvn liquibase: update: теперь, если мы посмотрим на результат в схеме базы данных, мы увидим следующие таблицы:
Мы видим, что наши таблицы с данными создаются. Мы также видим еще две таблицы: «DATABASECHANGELOG» и «DATABASECHANGELOGLOCK». Они используются Liquibase для определения состояния базы данных. Если я разверну файл WAR с источником данных в этой базе данных, Liquibase увидит, что сценарии уже запущены, и не выполнит их снова. Однако, если я удалю таблицы, сценарии будут выполнены так же, как и для новой базы данных. Как видите, это может упростить развертывание новых выпусков вашего программного обеспечения, по крайней мере, части базы данных.