محتويات الدورة

SQL Server / المتوسط / الدرس 7

القيود والمعاملات ومعالجة الأخطاء

اجمع تغييرات متعددة في نتيجة عمل واحدة باستخدام القواعد التصريحية والمعاملات الصريحة وXACT_ABORT وTRY/CATCH وXACT_STATE وTHROW بصورة مسؤولة.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • اختيار قيود للثوابت الدائمة.
  • شرح التثبيت والتراجع وحالة المعاملة.
  • تصميم حد لمعالجة الأخطاء يمتلك المعاملة.

افرض الثوابت الدائمة

تحمي PRIMARY KEY وUNIQUE وFOREIGN KEY وNOT NULL وCHECK ثوابت مختلفة. استخدمها حتى لو تحقق التطبيق من القاعدة نفسها، فقد تكتب خدمات أو عمليات استيراد أخرى لاحقاً. يرفض CHECK النتيجة FALSE لكنه قد يسمح بـ UNKNOWN، لذلك لا يغني CHECK (Quantity > 0) عن NOT NULL. سمّ القيود بوضوح لربط الفشل بقاعدته.

لا تجعل المعاملة قيمة غير صالحة مقبولة؛ فالقيود وحدود المعاملة متكاملان. في التحويل يجب أن يراعي كل رصيد قواعده المحلية، وأن يثبت الخصم والإضافة معاً. وقد تحتاج قواعد عابرة للصفوف إلى استراتيجية معاملة مدروسة بدلاً من CHECK يخفي سلوكاً إجرائياً يصل إلى صفوف أخرى.

اختر الوحدة الذرية

تفتح BEGIN TRANSACTION معاملة صريحة وتقبل COMMIT تغييراتها وتلغيها ROLLBACK. يستخدم SQL Server عادة التثبيت التلقائي للعبارات المنفردة خارج معاملة صريحة. لا تشكل عبارتان ناجحتان تلقائيتا التثبيت عملية عمل ذرية واحدة. قصّر مدة المعاملة وأبعد تفاعل المستخدم ونداءات HTTP البعيدة عن فترة الاحتفاظ بموارد القاعدة.

يستخدم المثال جدولاً مؤقتاً محلياً لأن تعديلاته تشارك في التراجع؛ ولا تفترض أن سلوك متغيرات الجداول يصلح لإظهار الأثر نفسه. يبقى الرصيد النهائي 100 بعد التراجع. هذا عرض نظري معزول، وليس توجيهاً لإنشاء كائنات على خادم مضبوط قائم.

sql التراجع عن تعديل جدول مؤقت
CREATE TABLE #Balance (Id int PRIMARY KEY, Amount decimal(10,2));
INSERT #Balance VALUES (1,100);
BEGIN TRANSACTION;
UPDATE #Balance SET Amount=Amount-20 WHERE Id=1;
ROLLBACK TRANSACTION;
SELECT Amount FROM #Balance WHERE Id=1;
DROP TABLE #Balance;
الناتج المتوقع
Amount
100.00

يتراجع التحديث بينما يبقى الإدراج السابق للمعاملة، ثم يحذف الجدول المؤقت صراحة.

عالج الفشل دون إخفائه

يمكن للوحدة التي تمتلك المعاملة ضبط XACT_ABORT ON وبدء العمل داخل TRY والتثبيت عند النجاح، ثم التراجع داخل CATCH عندما لا تساوي XACT_STATE() صفراً وإعادة إطلاق الخطأ. تعيد XACT_STATE القيمة 1 لمعاملة قابلة للتثبيت و-1 لمعاملة نشطة غير قابلة للتثبيت و0 عند غيابها. لا تنقذ COMMIT معاملة غير قابلة للتثبيت.

تحافظ THROW دون معاملات داخل CATCH على الخطأ الأصلي. تؤثر XACT_ABORT في أخطاء تنفيذ عديدة وتحترمها THROW، لكنها لا تجعل جميع أخطاء الترجمة أو انقطاع الاتصال قابلة للالتقاط. يطلق المثال خطأ مستخدم عمداً ويعرض رقمه بعد التنظيف. يظل على التطبيق ملاحظة الفشل المُعاد.

sql فحص الحالة بعد تراجع مقصود
SET XACT_ABORT ON;
BEGIN TRY
 BEGIN TRANSACTION;
 THROW 50001, 'Training rule rejected.', 1;
 COMMIT TRANSACTION;
END TRY
BEGIN CATCH
 IF XACT_STATE()<>0 ROLLBACK TRANSACTION;
 SELECT ERROR_NUMBER() AS error_number, XACT_STATE() AS after_cleanup;
END CATCH;
الناتج المتوقع
error_number after_cleanup
50001        0

يعرض المقطع التعليمي الحالة بدلاً من إعادة الإطلاق؛ وينبغي عادة استخدام THROW بعد التنظيف في حد المعاملة الفعلي.

حدد مالك المعاملة

قد يُستدعى إجراء مخزن داخل معاملة قائمة. تزيد BEGIN TRANSACTION المتداخلة @@TRANCOUNT، لكن COMMIT الداخلية لا تجعل التغييرات دائمة مستقلة. وقد تتراجع ROLLBACK غير المؤهلة عن المعاملة كلها. لذلك يجب أن يوثق الإجراء هل يمتلك المعاملة أم يشارك في وحدة يملكها المستدعي.

لا تنسخ قالب امتلاك المعاملة إلى كل إجراء مساعد. إما أن تشترط عدم وجود معاملة محيطة وتفرض العقد، أو تنفذ استراتيجية مشاركة ونقاط حفظ مراجعة مع معالجة واضحة للحالة غير القابلة للتثبيت. لا تجعل نقاط الحفظ المعاملة غير القابلة للتثبيت قابلة له. اختبر الاستدعاء المستقل والمتداخل؛ فاختلاف عدد المعاملات خطأ في الواجهة.

اختبر مسار الفشل صراحة

ضع فشلاً مقصوداً بعد أول تغييرين مترابطين وتحقق من عدم بقاء أي منهما. اختبر كذلك المفتاح المكرر والأب الغائب والمبلغ غير الصالح والتحديث المشروط الذي لا يعدل صفاً. لا يعد الصفر استثناء تلقائياً، لذا قد تحتاج عملية العمل إلى THROW صريحة قبل تثبيت عمل ناقص.

احفظ رقم الخطأ والإجراء والسطر في سجلات موثوقة وأعد استجابة مناسبة للتطبيق. لا تبتلع الخطأ وتعلن النجاح لمجرد اكتمال التراجع. ميّز الطلب المرفوض تجارياً من قاعدة غير متاحة ومن نتيجة مجهولة بعد فقد الاتصال. يشمل عقد المعاملة المتين هذه النتائج كلها لا النتيجة العادية وحدها.

الأخطاء الشائعة وإصلاحها

The transaction cannot be committed.

لماذا يحدث؟
ترك الخطأ XACT_STATE() بالقيمة -1.
كيف تصلحه؟
تراجع وأعد الفشل.
كيف تتجنب تكراره؟
افحص الحالة داخل CATCH المالكة للمعاملة.

A CHECK accepted NULL.

لماذا يحدث؟
أنتج الشرط UNKNOWN.
كيف تصلحه؟
أضف NOT NULL عندما تكون الخاصية مطلوبة.
كيف تتجنب تكراره؟
اختبر المفقود وغير الصالح مستقلاً.

An inner rollback erased caller work.

لماذا يحدث؟
لم توثق ملكية المعاملة.
كيف تصلحه؟
اعتمد عقد امتلاك أو مشاركة واضحاً.
كيف تتجنب تكراره؟
اختبر الاستدعاء المتداخل صراحة.

اختبر فهمك

1. يعدل الخصم صفاً ولا تعدل الإضافة صفاً. هل يجوز التثبيت؟

اعرض الحل المشروح

لا إذا كانا مطلوبين لتحويل واحد. احفظ عدد صفوف كل منهما وأطلق خطأ عمل عند الاختلاف كي تتراجع CATCH المالكة عن العملية كلها.

2. هل تحمي COMMIT الداخلية عملها من تراجع خارجي لاحق؟

اعرض الحل المشروح

لا؛ فأعداد المعاملات المتداخلة ليست تثبيتات دائمة مستقلة. تتحكم الوحدة الخارجية في الديمومة؛ وثّق المشاركة بدلاً من اعتبار COMMIT الداخلية عملية حفظ مستقلة.

أهم ما تعلمته

  • تحل القيود والمعاملات مشكلات متكاملة.
  • يجب أن يحافظ تنظيف التراجع على الإبلاغ عن الفشل.
  • ملكية المعاملة جزء من عقد الإجراء.

المراجع الرسمية