انتقل إلى المحتوى الرئيسي

الفصل 4: الترحيل باستخدام Liquibase

مقدمة​

Liquibase هو بديل شائع لـ Flyway. بينما يستخدم Flyway بشكل رئيسي SQL الخام، يقدم Liquibase تنسيقًا محايدًا لقاعدة البيانات (XML، YAML، JSON) يمكن تحويله إلى SQL لعدة قواعد بيانات.


🎯 أهداف الفصل​

في نهاية هذا الفصل، ستعرف:

  1. ✅ فهم الفروقات بين Flyway وLiquibase
  2. ✅ إعداد Liquibase مع Spring Boot
  3. ✅ إنشاء سجلات التغيير في XML، YAML وSQL
  4. ✅ استخدام التراجعات التلقائية
  5. ✅ الاختيار بين Flyway وLiquibase

1. Flyway مقابل Liquibase​

مقارنة سريعة​

الجانبFlywayLiquibase
التنسيق الرئيسيSQL الأصليXML، YAML، JSON، SQL
منحنى التعلمسهل جدًامتوسط
قابلية النقل بين قواعد البياناتمنخفضة (SQL محدد)عالية
التراجعيدويتلقائي لبعض العمليات
المجتمعواسع جدًاواسع
Spring Bootتكامل ممتازتكامل ممتاز

متى تختار Flyway؟​

✅ استخدم Flyway إذا:

  • كنت تستخدم قاعدة بيانات واحدة
  • تفضل SQL الأصلي
  • تريد البساطة القصوى
  • فريقك يعرف SQL جيدًا

متى تختار Liquibase؟​

✅ استخدم Liquibase إذا:

  • تحتاج لدعم عدة قواعد بيانات (PostgreSQL، MySQL، Oracle...)
  • تريد تراجعات تلقائية
  • تفضل التنسيقات التصريحية (YAML، XML)
  • لديك تغييرات معقدة لإدارتها

2. التثبيت​

تبعية Maven​

<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
حذر

تنبيه: لا تستخدم Flyway وLiquibase معًا في نفس المشروع!


3. هيكل الملفات​

الهيكل الموصى به​

src/
└── main/
└── resources/
└── db/
└── changelog/
├── db.changelog-master.xml # الملف الرئيسي
├── changes/
│ ├── 001-create-users.xml
│ ├── 002-add-email.xml
│ └── 003-create-orders.xml
└── data/
└── initial-data.xml # البيانات الأولية

الملف الرئيسي (نقطة الدخول)​

<!-- db.changelog-master.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-latest.xsd">

<!-- تضمين ملفات التغييرات -->
<include file="db/changelog/changes/001-create-users.xml"/>
<include file="db/changelog/changes/002-add-email.xml"/>
<include file="db/changelog/changes/003-create-orders.xml"/>

<!-- أو تضمين مجلد كامل -->
<includeAll path="db/changelog/data/"/>

</databaseChangeLog>

4. تنسيق XML​

إنشاء جدول​

<!-- 001-create-users.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-latest.xsd">

<changeSet id="1" author="dev">
<comment>إنشاء جدول المستخدمين</comment>

<createTable tableName="users">
<column name="id" type="BIGINT" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="username" type="VARCHAR(50)">
<constraints nullable="false" unique="true"/>
</column>
<column name="password" type="VARCHAR(100)">
<constraints nullable="false"/>
</column>
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
</createTable>

<!-- تراجع تلقائي: DROP TABLE users -->
</changeSet>

</databaseChangeLog>

إضافة عمود​

<!-- 002-add-email.xml -->
<databaseChangeLog ...>

<changeSet id="2" author="dev">
<comment>إضافة عمود البريد الإلكتروني</comment>

<addColumn tableName="users">
<column name="email" type="VARCHAR(100)">
<constraints unique="true"/>
</column>
</addColumn>

<!-- تراجع تلقائي: DROP COLUMN email -->
</changeSet>

</databaseChangeLog>

إنشاء فهرس​

<changeSet id="3" author="dev">
<createIndex tableName="users" indexName="idx_users_email">
<column name="email"/>
</createIndex>
</changeSet>

إدخال بيانات​

<changeSet id="4" author="dev">
<insert tableName="users">
<column name="username" value="admin"/>
<column name="password" value="$2a$10$hashedpassword"/>
<column name="email" value="admin@example.com"/>
</insert>

<!-- تراجع يدوي مطلوب -->
<rollback>
DELETE FROM users WHERE username = 'admin';
</rollback>
</changeSet>

5. تنسيق YAML​

أكثر قابلية للقراءة من XML!

إنشاء جدول​

# 001-create-users.yaml
databaseChangeLog:
- changeSet:
id: 1
author: dev
comment: إنشاء جدول المستخدمين
changes:
- createTable:
tableName: users
columns:
- column:
name: id
type: BIGINT
autoIncrement: true
constraints:
primaryKey: true
nullable: false
- column:
name: username
type: VARCHAR(50)
constraints:
nullable: false
unique: true
- column:
name: password
type: VARCHAR(100)
constraints:
nullable: false
- column:
name: created_at
type: TIMESTAMP
defaultValueComputed: CURRENT_TIMESTAMP

إضافة عمود​

# 002-add-email.yaml
databaseChangeLog:
- changeSet:
id: 2
author: dev
comment: إضافة البريد الإلكتروني إلى المستخدمين
changes:
- addColumn:
tableName: users
columns:
- column:
name: email
type: VARCHAR(100)
constraints:
unique: true

الملف الرئيسي في YAML​

# db.changelog-master.yaml
databaseChangeLog:
- include:
file: db/changelog/changes/001-create-users.yaml
- include:
file: db/changelog/changes/002-add-email.yaml
- includeAll:
path: db/changelog/data/

6. تنسيق SQL (مثل Flyway)​

يمكنك أيضًا استخدام SQL الخام:

-- 001-create-users.sql
-- liquibase formatted sql

-- changeset dev:1
-- comment: إنشاء جدول المستخدمين
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- rollback DROP TABLE users;
-- 002-add-email.sql
-- liquibase formatted sql

-- changeset dev:2
ALTER TABLE users ADD COLUMN email VARCHAR(100) UNIQUE;

-- rollback ALTER TABLE users DROP COLUMN email;

7. إعداد Spring Boot​

الإعداد الأدنى​

# application.properties
spring.liquibase.enabled=true
spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.xml

الإعداد الكامل​

# تفعيل Liquibase
spring.liquibase.enabled=true

# ملف سجل التغيير الرئيسي
spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.yaml

# المخططات
spring.liquibase.default-schema=public
spring.liquibase.liquibase-schema=public

# السياقات (dev، test، prod)
spring.liquibase.contexts=dev

# التسميات
spring.liquibase.labels=

# التراجع في حالة الفشل
spring.liquibase.rollback-file=rollback.sql

تنسيق YAML​

spring:
liquibase:
enabled: true
change-log: classpath:db/changelog/db.changelog-master.yaml
default-schema: public
contexts: dev

8. التراجعات​

التراجع التلقائي​

Liquibase يولد التراجعات تلقائيًا لـ:

العمليةالتراجع التلقائي
createTableDROP TABLE
addColumnDROP COLUMN
createIndexDROP INDEX
addForeignKeyDROP FOREIGN KEY
insert❌ (يدوي)
update❌ (يدوي)
delete❌ (يدوي)
sql❌ (يدوي)

التراجع اليدوي​

<changeSet id="5" author="dev">
<update tableName="users">
<column name="status" value="ACTIVE"/>
<where>status IS NULL</where>
</update>

<!-- تراجع يدوي إلزامي -->
<rollback>
<update tableName="users">
<column name="status" valueComputed="NULL"/>
<where>status = 'ACTIVE'</where>
</update>
</rollback>
</changeSet>

تنفيذ تراجع​

# تراجع عن آخر مجموعة تغييرات
mvn liquibase:rollback -Dliquibase.rollbackCount=1

# تراجع حتى علامة
mvn liquibase:rollback -Dliquibase.rollbackTag=v1.0

# تراجع حتى تاريخ
mvn liquibase:rollback -Dliquibase.rollbackDate=2025-01-01

9. السياقات والتسميات​

السياقات​

تنفيذ بعض مجموعات التغييرات فقط في بيئات معينة:

<!-- فقط في dev -->
<changeSet id="10" author="dev" context="dev">
<insert tableName="users">
<column name="username" value="testuser"/>
</insert>
</changeSet>

<!-- فقط في prod -->
<changeSet id="11" author="dev" context="prod">
<insert tableName="config">
<column name="key" value="feature.flag"/>
<column name="value" value="true"/>
</insert>
</changeSet>
# application-dev.properties
spring.liquibase.contexts=dev

# application-prod.properties
spring.liquibase.contexts=prod

التسميات​

تجميع مجموعات التغييرات حسب الميزة:

<changeSet id="20" author="dev" labels="user-feature">
<!-- تغييرات متعلقة بالمستخدمين -->
</changeSet>

<changeSet id="21" author="dev" labels="order-feature">
<!-- تغييرات متعلقة بالطلبات -->
</changeSet>

10. جدول DATABASECHANGELOG​

Liquibase يتتبع التغييرات في جدول:

SELECT * FROM DATABASECHANGELOG;
IDAUTHORFILENAMEDATEEXECUTEDORDEREXECUTEDEXECTYPEMD5SUMDESCRIPTION
1dev001-create-users.xml2025-01-151EXECUTEDabc123createTable tableName=users
2dev002-add-email.xml2025-01-152EXECUTEDdef456addColumn tableName=users

11. أوامر Maven​

<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<configuration>
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
</configuration>
</plugin>
# عرض الحالة
mvn liquibase:status

# تطبيق التغييرات
mvn liquibase:update

# توليد SQL بدون تنفيذه
mvn liquibase:updateSQL

# التراجع
mvn liquibase:rollback -Dliquibase.rollbackCount=1

# إنشاء علامة
mvn liquibase:tag -Dliquibase.tag=v1.0

# توليد سجل التغيير من قاعدة بيانات موجودة
mvn liquibase:generateChangeLog

12. ملخص​

النقاط الرئيسية​

المفهومالوصف
ChangeLogالملف الرئيسي الذي يسرد التغييرات
ChangeSetتغيير ذري (معرف + مؤلف فريد)
السياقاتتصفية مجموعات التغييرات حسب البيئة
التسمياتتجميع مجموعات التغييرات حسب الميزة
التراجعإلغاء التغييرات (تلقائي أو يدوي)

متى تستخدم أي أداة؟​

الإعداد الأدنى​

# application.yml مع Liquibase
spring:
liquibase:
enabled: true
change-log: classpath:db/changelog/db.changelog-master.yaml

ملف رئيسي بسيط​

# db.changelog-master.yaml
databaseChangeLog:
- includeAll:
path: db/changelog/changes/

🎯 الخطوة التالية​

لديك الآن كل النظرية! حان الوقت للتطبيق مع الأعمال العملية.

➡️ TP7.1: إعداد Datasource وPool


⬅️ العودة إلى الوحدة 7