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

اختبار: المعاملات والترحيلات

اختبر معرفتك بالمعاملات، Flyway وLiquibase.

30 سؤالًا - انقر على كل سؤال لكشف الإجابة.


الأسئلة 1-10: المعاملات​

السؤال 1: ما هي المعاملة؟

الإجابة: المعاملة هي وحدة عمل ذرية تضمن ACID:

  • الذرية: الكل أو لا شيء
  • التناسق: حالة صالحة قبل/بعد
  • العزل: معاملات مستقلة
  • الدوام: مستمرة بعد الالتزام

السؤال 2: كيف تعلن عن طريقة معاملية؟

الإجابة:

@Service
public class TransferService {

@Transactional
public void transfer(Long from, Long to, BigDecimal amount) {
accountRepository.debit(from, amount);
accountRepository.credit(to, amount);
}
}

السؤال 3: ماذا يحدث إذا تم رفع استثناء في معاملة؟

الإجابة:

  • RuntimeException (غير مفحوصة): تراجع تلقائي
  • Exception (مفحوصة): لا تراجع افتراضيًا
@Transactional(rollbackFor = Exception.class)  // تراجع أيضًا للمفحوصة
public void doWork() throws IOException { }

السؤال 4: كيف تجبر على التراجع لاستثناء مفحوص؟

الإجابة:

@Transactional(rollbackFor = {IOException.class, CustomException.class})
public void process() throws IOException { }

// أو تراجع للجميع
@Transactional(rollbackFor = Exception.class)

السؤال 5: كيف تمنع التراجع لاستثناء RuntimeException؟

الإجابة:

@Transactional(noRollbackFor = BusinessException.class)
public void process() {
// BusinessException لن يسبب تراجع
}

السؤال 6: ما هي مستويات عزل المعاملات؟

الإجابة:

المستوىالوصف
READ_UNCOMMITTEDيقرأ البيانات غير الملتزمة
READ_COMMITTEDيقرأ فقط الملتزمة (افتراضي)
REPEATABLE_READقراءات مكررة متطابقة
SERIALIZABLEعزل كامل (أبطأ)
@Transactional(isolation = Isolation.SERIALIZABLE)

السؤال 7: ما هي انتشار المعاملات؟

الإجابة: كيف تتصرف المعاملة عند استدعائها من أخرى:

@Transactional(propagation = Propagation.REQUIRED)  // افتراضي
// يستخدم المعاملة الحالية أو ينشئ واحدة جديدة

@Transactional(propagation = Propagation.REQUIRES_NEW)
// ينشئ دائمًا معاملة جديدة

@Transactional(propagation = Propagation.MANDATORY)
// يجب أن يتم استدعاؤها في معاملة موجودة

السؤال 8: متى تستخدم REQUIRES_NEW؟

الإجابة: عندما يجب الالتزام بعملية بشكل مستقل:

@Transactional
public void processOrder(Order order) {
orderService.save(order);
auditService.logAction(order); // يجب أن تستمر حتى لو فشل الطلب
}

@Service
public class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logAction(Order order) {
// معاملة جديدة مستقلة
}
}

السؤال 9: لماذا لا يعمل @Transactional على طريقة خاصة؟

الإجابة: يستخدم Spring وكلاء AOP الذين يعترضون فقط المكالمات الخارجية. الطرق الخاصة والمكالمات الداخلية لا تمر عبر الوكيل.

public void methodA() {
methodB(); // مكالمة داخلية - لا وكيل!
}

@Transactional
private void methodB() { } // لا يعمل

السؤال 10: كيف تحل مشكلة المكالمات الداخلية؟

الإجابة:

  1. استخراج في bean آخر
  2. استخدام self-injection
  3. استخدام TransactionTemplate
// الخيار 1: bean آخر
@Service
public class HelperService {
@Transactional
public void doWork() { }
}

// الخيار 2: TransactionTemplate
transactionTemplate.execute(status -> {
// كود المعاملة
return result;
});

الأسئلة 11-20: Flyway​

السؤال 11: ما هو Flyway؟

الإجابة: Flyway هو أداة لترحيل قواعد البيانات:

  • يقوم بتحديد إصدار مخطط قاعدة البيانات
  • يطبق الترحيلات بالترتيب
  • يحتفظ بتاريخ الترحيلات
  • يدعم SQL وJava

السؤال 12: كيف تسمي ملفات ترحيل Flyway؟

الإجابة: الاتفاقية: V\{version\}__\{description\}.sql

V1__create_users_table.sql
V2__add_email_column.sql
V3__create_orders_table.sql
V1.1__add_index.sql (تحت الإصدار)

الشرطة السفلية المزدوجة __ إلزامية.


السؤال 13: أين تضع ملفات الترحيل؟

الإجابة: افتراضيًا: src/main/resources/db/migration/

src/main/resources/
└── db/
└── migration/
├── V1__create_users.sql
└── V2__add_orders.sql

السؤال 14: أي جدول يستخدمه Flyway للتتبع؟

الإجابة: flyway_schema_history يحتوي على:

  • الإصدار
  • الوصف
  • المجموع الاختباري
  • تاريخ التنفيذ
  • النجاح/الفشل

السؤال 15: كيف تقوم بتكوين Flyway في Spring Boot؟

الإجابة:

spring:
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true
validate-on-migrate: true

السؤال 16: ما هي الترحيلات المتكررة؟

الإجابة: الترحيل الذي يتم إعادة تنفيذه إذا تغير محتواه:

R__create_views.sql  (R بدلاً من V)

يستخدم للمشاهد، الإجراءات المخزنة، بيانات المرجع.


السؤال 17: كيف تلغي ترحيل Flyway؟

الإجابة: Flyway Community لا يدعم التراجع. الحلول:

  1. إنشاء ترحيل جديد يلغي
  2. استخدام Flyway Teams (مدفوع)
  3. استعادة نسخة احتياطية
-- V3__undo_v2.sql
ALTER TABLE users DROP COLUMN email;

السؤال 18: كيف تتجاهل ترحيلًا تم تطبيقه يدويًا؟

الإجابة:

spring:
flyway:
baseline-on-migrate: true
baseline-version: 1

أو أمر CLI: flyway baseline


السؤال 19: كيف تنفذ كود Java في ترحيل؟

الإجابة:

public class V3__ComplexMigration implements JavaMigration {

@Override
public void migrate(Context context) throws Exception {
try (Statement stmt = context.getConnection().createStatement()) {
// ترحيل معقد في Java
}
}
}

السؤال 20: كيف تتحقق من صحة الترحيلات دون تنفيذها؟

الإجابة:

# CLI
flyway validate

# أو في التكوين
spring:
flyway:
validate-on-migrate: true

يتحقق من أن المجموعات الاختبارية تتطابق.


الأسئلة 21-30: Liquibase​

السؤال 21: ما الفرق بين Flyway وLiquibase؟

الإجابة:

FlywayLiquibase
SQL أو JavaXML، YAML، JSON، SQL
أبسطأكثر مرونة
لا تراجع (Community)تراجع مدمج
تحديد إصدار خطيمجموعات التغييرات مع معرف

السؤال 22: كيف تنظم ملف changelog في Liquibase؟

الإجابة:

# db/changelog/db.changelog-master.yaml
databaseChangeLog:
- changeSet:
id: 1
author: dev
changes:
- createTable:
tableName: users
columns:
- column:
name: id
type: bigint
autoIncrement: true
constraints:
primaryKey: true

السؤال 23: كيف يتتبع Liquibase التغييرات المطبقة؟

الإجابة: عبر الجداول:

  • DATABASECHANGELOG: تاريخ مجموعات التغييرات
  • DATABASECHANGELOGLOCK: قفل لمنع التنفيذ المتوازي

السؤال 24: كيف تحدد تراجعًا في Liquibase؟

الإجابة:

- changeSet:
id: 1
author: dev
changes:
- addColumn:
tableName: users
columns:
- column:
name: phone
type: varchar(20)
rollback:
- dropColumn:
tableName: users
columnName: phone

السؤال 25: كيف تنفذ تراجعًا في Liquibase؟

الإجابة:

# تراجع عن آخر مجموعة تغييرات
liquibase rollbackCount 1

# تراجع حتى علامة
liquibase rollback myTag

# تراجع حتى تاريخ
liquibase rollbackToDate 2024-01-01

السؤال 26: كيف تقوم بتكوين Liquibase في Spring Boot؟

الإجابة:

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

السؤال 27: كيف تستخدم السياقات في Liquibase؟

الإجابة: تنفيذ بعض مجموعات التغييرات حسب البيئة:

- changeSet:
id: 1
author: dev
context: dev, test # فقط في dev وtest
changes:
- insert:
tableName: users
columns:
- column: {name: name, value: 'Test User'}
spring:
liquibase:
contexts: dev

السؤال 28: كيف تولد changelog من قاعدة بيانات موجودة؟

الإجابة:

liquibase generateChangeLog \
--changeLogFile=changelog.yaml \
--url=jdbc:postgresql://localhost/mydb \
--username=user \
--password=pass

السؤال 29: كيف تتحقق من صحة changelog دون تنفيذه؟

الإجابة:

liquibase validate

يتحقق من صحة الصياغة والمجموعات الاختبارية.


السؤال 30: كيف تضع علامة على إصدار للتراجع؟

الإجابة:

- changeSet:
id: release-1.0
author: dev
changes:
- tagDatabase:
tag: v1.0.0
# تراجع إلى هذه العلامة
liquibase rollback v1.0.0

النتيجة​

النتيجةالمستوى
27-30ممتاز - إتقان المعاملات والترحيلات
21-26جيد - بعض المراجعات
15-20متوسط - أعد قراءة الفصول
أقل من 15بحاجة إلى مراجعة

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