مقدمة
Liquibase هو نظام للتحكم في إصدار قاعدة البيانات ، وهذا يتعلق بشكل أساسي بالهيكل ، وإلى حد أقل ، محتويات قاعدة البيانات. في الوقت نفسه ، وصف قاعدة البيانات من ناحية مجردة تمامًا ويسمح باستخدام قواعد بيانات إدارة قواعد البيانات المختلفة في المستوى الأدنى ، ومن ناحية أخرى ، يمكنك دائمًا التبديل إلى لهجة SQL الخاصة بنظام قاعدة بيانات إدارة قواعد البيانات (DBMS) ، والذي يتميز بالمرونة التامة. Liquibase هو مشروع مفتوح المصدر تم إنشاؤه ويستخدم بنشاط خارج بيئة Java الأصلية ولا يتطلب معرفة متعمقة من Java للعمل. تاريخياً ، استخدم تنسيق XML لوصف البنية الأساسية والتغييرات الأساسية ، ولكن الآن يتم دعم YAML و JSON بشكل متوازٍ.
في هذه المقالة ، سنوجز باختصار تجربة الأجيال السابقة وسنركز على العمل مع Liquibase باستخدام Maven. سوف نستخدم Ubuntu كنظام تشغيل اختبار.
مقالات أخرى حول Liquibase
بيئة الإعداد
هناك عدة طرق لبدء تشغيل Liquibase ، إلا أنه من الأنسب استخدام Maven أو Gradle.
sudo apt install maven mvn -version
هنا pom.xml بمثابة Makefile - أنه يحتوي بالفعل على جميع التبعيات والإعدادات والتوصيفات اللازمة.
pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test.db</groupId> <artifactId>db</artifactId> <version>1.0.0</version> <name>db</name> <description>Test Database</description> <packaging>pom</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <slf4j.version>1.7.24</slf4j.version> <logback.version>1.2.3</logback.version> <liquibase.version>3.6.2</liquibase.version> <postgresql.version>42.2.5</postgresql.version> <snakeyaml.version>1.23</snakeyaml.version> </properties> <dependencies> <!--Logging--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> <!--JDBC drivers--> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>${postgresql.version}</version> </dependency> <dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> <version>${liquibase.version}</version> </dependency> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>${snakeyaml.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>${liquibase.version}</version> <configuration> <propertyFile>${profile.propertyFile}</propertyFile> <changeLogFile>${profile.changeLogFile}</changeLogFile> <dataDir>${profile.dataDir}</dataDir> <!-- log --> <verbose>${profile.verbose}</verbose> <logging>${profile.logging}</logging> <promptOnNonLocalDatabase>false</promptOnNonLocalDatabase> </configuration> </plugin> </plugins> </build> <profiles> <!-- Development settings, -Denv=dev --> <profile> <id>dev</id> <activation> <property> <name>env</name> <value>dev</value> </property> </activation> <properties> <profile.propertyFile>dev/liquibase.properties</profile.propertyFile> <profile.changeLogFile>dev/master.xml</profile.changeLogFile> <profile.dataDir>dev/data</profile.dataDir> <profile.verbose>true</profile.verbose> <profile.logging>debug</profile.logging> </properties> </profile> <!-- Production settings, -Denv=prod --> <profile> <id>prod</id> <activation> <property> <name>env</name> <value>prod</value> </property> </activation> <properties> <profile.propertyFile>prod/liquibase.properties</profile.propertyFile> <profile.changeLogFile>prod/master.xml</profile.changeLogFile> <profile.dataDir>prod/data</profile.dataDir> <profile.verbose>false</profile.verbose> <profile.logging>info</profile.logging> </properties> </profile> </profiles> </project>
نطلق التحديث
بعد الانتهاء من pom.xml ، يمكننا البدء في تحديث قاعدة البيانات - الأمر liquibase: update.
لهذا نحتاج:
- ملف liquibase.properties مع إعدادات للاتصال بقاعدة البيانات (اسم المستخدم / كلمة المرور وربما غيرها من المعالم)
- ملف XML مع التغييرات الأساسية
- ش تحديث قاعدة البيانات النصي لبدء التشغيل
ملف إعدادات اتصال قاعدة البيانات
liquibase.properties
username=test password=test referenceUsername=test # #url=jdbc:postgresql://dev/test #referenceUrl=jdbc:postgresql://dev/test_reference
تغييرات قاعدة الملف
المفهوم الرئيسي لل fluibase هو ما يسمى التغييرات الأساسية (Chanets). يمكن أن تشمل كل من التغييرات الهيكلية وتغيير البيانات. يستخدم Liquibase جداول databasechangelog و databasechangeloglock لمراقبة التغييرات المطبقة.
<?xml version="1.1" encoding="UTF-8" standalone="no"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd"> <changeSet context="legacy" author="author (generated)" id="1"> <createTable tableName="test"> <column autoIncrement="true" name="id" type="SERIAL"> <constraints nullable="false"/> </column> <column name="user_name" type="VARCHAR(255)"/> <column name="preferences" type="TEXT"/> </createTable> </changeSet> </databaseChangeLog>
تحديث قاعدة البيانات النصي لبدء التشغيل
هنا liquibase: يتم تنفيذ التحديث لملف تعريف dev والقاعدة من liquibase.url ، المحدد في تنسيق JDBC القياسي. بعد التحديث ، يظهر الجدول المشار إليه في changeSet وجدولين للخدمة databasechangelog و databasechangeloglock في قاعدة البيانات .
#!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"
إنشاء SQL دون تحديث قاعدة البيانات
في بعض الأحيان ، قبل بدء التغييرات ، تحتاج إلى إلقاء نظرة على محتويات الطلبات التي تم إنشاؤها. و liquibase: updateSQL و liquibase: أوامر rollbackSQL هي لهذا الغرض المقصود.
#!/usr/bin/env bash mvn liquibase:updateSQL\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified" > /tmp/script.sql
المزيد عن changeSet
يمكن أن تكون التغييرات بتنسيقات مختلفة ، بما في ذلك sql العادية أو في ملف منفصل.
قد يتضمن كل تغيير مقطعًا للتراجع يسمح لك باستعادة التغييرات باستخدام الأمر liquibase: rollback . بالإضافة إلى ذلك ، يمكنك استخدام tagDatabase لتمييز التغييرات ، على سبيل المثال ، للتراجع هناك بسهولة أكبر.
<changeSet context="legacy" author="author (generated)" id="1"> <createTable tableName="test"> <column autoIncrement="true" name="id" type="SERIAL"> <constraints primaryKey="true" primaryKeyName="test_pkey"/> </column> <column name="c1" type="VARCHAR(255)"/> <column name="c2" type="INTEGER"/> <column name="c3" type="SMALLINT"/> <column name="c4" type="VARCHAR(255)"/> <column name="c5" type="TEXT"/> <column name="c6" type="VARCHAR(255)"/> </createTable> </changeSet>
مزود المضمنة
<changeSet context="legacy" author="author" id="1-domain-some-domain"> <sql> CREATE DOMAIN public.some_domain AS bigint; ALTER DOMAIN public.some_domain OWNER TO test; </sql> <rollback> DROP DOMAIN public.some_domain; </rollback> </changeSet>
ملف SQL
<changeSet context="legacy" author="author" id="1-user"> <sqlFile dbms="postgresql" path="sql/some.sql" relativeToChangelogFile="true" /> <rollback> delete from "some"; </rollback> </changeSet>
العلامات
<changeSet context="legacy" author="author" id="1-initial-changeset"> <tagDatabase tag="initial"/> </changeSet>
إطلاق السياقات
لإدارة أكثر ملاءمة للتكوينات المختلفة ، على سبيل المثال ، التطوير / الإنتاج ، يمكن استخدام السياقات. يتم تحديد السياق في سمة changeSet للسياق ثم يتم تشغيله بواسطة Maven باستخدام معلمة -Dcontexts.
التغيير مع السياق
<changeSet context="legacy" author="author" id="1-initial-changeset"> <tagDatabase tag="initial"/> </changeSet>
تحريك تغييرات السياق
#!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"\ -Dliquibase.contexts=non-legacy
دحر التغييرات
العملية هي عكس التحديث ، وفي معظم الحالات يتم دعمها تلقائيًا. بالنسبة للآخرين ، تكون المهمة ممكنة من خلال قسم الاستعادة. يتم تشغيله بواسطة الأمر liquibase: rollback.
التغيير مع التراجع
<changeSet context="legacy" author="author" id="1-domain-some-domain"> <sql> CREATE DOMAIN public.some_domain AS bigint; ALTER DOMAIN public.some_domain OWNER TO test; </sql> <rollback> DROP DOMAIN public.some_domain; </rollback> </changeSet>
إطلاق التراجع
#!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"\ -Dliquibase.contexts=non-legacy
مقارنة
في التطوير ، من الملائم استخدامه لمقارنة قاعدتي بيانات موجودتين للتغييرات التي تم إجراؤها. في الإعدادات (أو معلمات التشغيل) ، ستحتاج إلى إضافة رابط إلى قاعدة البيانات المرجعية والبيانات للوصول إليها.
liquibase.properties
referenceUsername=test referenceUrl=jdbc:postgresql://dev/test_reference
مقارنة الدائرة
مقارنة مخططات url و referenceUrl.
#!/usr/bin/env bash mvn liquibase:diff\ -Denv=dev\ -Dliquibase.referenceUrl="jdbc:postgresql://dev/test?prepareThreshold=0"\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.diffChangeLogFile=dev/diff.xml
إنقاذ المخطط
قد يكون من المفيد أيضًا حفظ مخطط قاعدة البيانات الحالي ، مع أو بدون بيانات. يجب ألا يغيب عن البال أن Liquibase يحفظ مخططًا لا يتطابق تمامًا مع الأصل ، على سبيل المثال ، يجب إضافة النطاقات المستخدمة أو الميراث بشكل منفصل (انظر القيود).
حفظ مخطط دون أخذ البيانات في الاعتبار
حفظ مخطط قاعدة بيانات موجودة.
#!/usr/bin/env bash mvn liquibase:generateChangeLog\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.outputChangeLogFile=dev/changelog.xml
حفظ مخطط مع البيانات
حفظ مخطط قاعدة بيانات موجودة مع البيانات.
#!/usr/bin/env bash mvn liquibase:generateChangeLog\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.outputChangeLogFile=dev/changelog.xml
القيود والمشاكل
العمل مع البيانات الثنائية في قاعدة البيانات
هناك بعض المشكلات المتعلقة بتحميل البيانات الثنائية ومقارنتها واستخدامها ، لا سيما مشكلة إنشاء التغييرات.
الوراثة والأعمدة المشتركة
شفرة المصدر
حلول بديلة
Flyway
جنبا إلى جنب مع Liquibase تحظى بشعبية في مجتمع جافا - http://flywaydb.org/documentation
سقيتش
بيرل مكافئ - http://sqitch.org
Fluentmigrator
النظير لـ .Net - https://github.com/schambers/fluentmigrator
دبجيني
التناظرية لروبي - http://dbgeni.appsintheopen.com/manual.html
التطبيقات
هيكل المشروع
pom.xml - maven makefile dev liquibase.properties - login/password etc master.xml - changesets
كيفية إضافة السائل إلى مشروع قائم
كيف تعمل التغييرات القاعدة
المزيد عن التحديث
المزيد عن تغيير الجيل
المزيد عن SQL مخصص
معالجة أنواع البيانات الخاصة بقاعدة البيانات
<createTable tableName="t_name"> ... <column name="doubleArray" type="DOUBLE_ARRAY"/> ... </createTable> <modifySql dbms="postgresql"> <replace replace="DOUBLE_ARRAY" with="double precision[][]"/> </modifySql>
أخرى