<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>قاعدة البيانات on Dev TLDRLSS</title>
        <link>https://dev.tldrlss.com/ar/categories/%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/</link>
        <description>Recent content in قاعدة البيانات on Dev TLDRLSS</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>ar</language>
        <lastBuildDate>Tue, 19 May 2026 18:10:00 +0800</lastBuildDate><atom:link href="https://dev.tldrlss.com/ar/categories/%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>لا تنخدع بعفوية SQLite! ما هي فخاخ الأنواع الديناميكية؟ ولماذا ALTER TABLE غير مكتمل؟ وكيف تبني بنية برمجية دفاعية في Node.js لترقية مخطط الجدول بدون ألم؟</title>
        <link>https://dev.tldrlss.com/ar/article/2026/05/sqlite-pitfall-intro/</link>
        <pubDate>Tue, 19 May 2026 18:10:00 +0800</pubDate>
        
        <guid>https://dev.tldrlss.com/ar/article/2026/05/sqlite-pitfall-intro/</guid>
        <description>&lt;img src="https://dev.tldrlss.com/global-assets/images/database/sqlite-type-pitfall-1.jpg" alt="Featured image of post لا تنخدع بعفوية SQLite! ما هي فخاخ الأنواع الديناميكية؟ ولماذا ALTER TABLE غير مكتمل؟ وكيف تبني بنية برمجية دفاعية في Node.js لترقية مخطط الجدول بدون ألم؟" /&gt;&lt;p&gt;تخيل سلة إعادة تدوير وضعت عليها بوضوح ملصقًا يقول &amp;quot;للزجاجات البلاستيكية فقط&amp;quot;، ولكن عندما يلقي شخص ما قطعة ورق داخلها، فإنها تقبلها بصمت دون كلمة احتجاج واحدة؟&lt;/p&gt;
&lt;p&gt;هذه هي التجربة المثيرة للقشعريرة التي يمر بها المطورون عندما يقابلون نظام أنواع &lt;code&gt;SQLite&lt;/code&gt; لأول مرة.&lt;/p&gt;
&lt;p&gt;إذا كنت معتادًا على أسلوب موظف الجمارك الصارم في &lt;code&gt;PostgreSQL&lt;/code&gt; (حيث يتم رفض الأنواع غير الصحيحة مباشرة من الدخول)، فإن عفوية وسهولة &lt;code&gt;SQLite&lt;/code&gt; قد تجعلك تشك في حياتك.&lt;/p&gt;
&lt;p&gt;والأكثر رعبًا من ذلك، عندما تريد &lt;strong&gt;تعديل بنية جدول&lt;/strong&gt;، ستخبرك قاعدة البيانات بالتالي:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;لا يمكن تعديل الجدول مباشرة. يرجى بناء منزل جديد، ونقل الأثاث إليه، ثم تفجير المنزل القديم.&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;تحت-الغطاء-تمتلك-sqlite-5-فئات-تخزين-فقط&#34;&gt;تحت الغطاء، تمتلك SQLite 5 فئات تخزين فقط
&lt;/h2&gt;&lt;p&gt;بغض النظر عن أسماء الأنواع الفخمة التي تعلن عنها في &lt;code&gt;CREATE TABLE&lt;/code&gt; مثل (&lt;code&gt;VARCHAR(255)&lt;/code&gt;، &lt;code&gt;BIGINT&lt;/code&gt;، &lt;code&gt;DECIMAL&lt;/code&gt;)، فإن &lt;code&gt;SQLite&lt;/code&gt; تحت الغطاء لا تتعرف إلا على &lt;strong&gt;فئات التخزين الخمس&lt;/strong&gt; التالية:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;فئة التخزين&lt;/th&gt;
          &lt;th&gt;الوصف&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;NULL&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;قيمة فارغة&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;INTEGER&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;عدد صحيح (يشغل تلقائيًا من 1 إلى 8 بايت اعتمادًا على حجم القيمة)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;REAL&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;رقم عشري عائم (ثابت 8 بايت)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;TEXT&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;سلسلة نصية (ترميز UTF-8 افتراضي)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;BLOB&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;كائن ثنائي كبير (يتم تخزينه تمامًا كما تم إدخاله)&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;الأنواع التي تحددها في الأعمدة &lt;strong&gt;هي مجرد &amp;quot;توصية&amp;quot; لـ &lt;code&gt;SQLite&lt;/code&gt; وليست &amp;quot;قواعد إلزامية&amp;quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;يطلق على هذا اسم &lt;strong&gt;&amp;quot;Type Affinity&amp;quot; (أفيونيتي النوع)&lt;/strong&gt;. ستحاول &lt;code&gt;SQLite&lt;/code&gt; تحويل بياناتك إلى النوع الموصى به، ولكن إذا لم تتمكن من ذلك، فستقوم بإدخال البيانات الأصلية على أي حال دون إظهار أي خطأ.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;يمكنك الإعلان عن عمود &lt;code&gt;age INTEGER&lt;/code&gt; في &lt;code&gt;SQLite&lt;/code&gt; ثم إدخال السلسلة النصية &lt;code&gt;&#39;ثمانية عشر عامًا للأبد&#39;&lt;/code&gt;؛ وسوف تقبله بكل سرور.&lt;/p&gt;
&lt;!--adsense--&gt;
&lt;h2 id=&#34;ثلاثة-فخاخ-أنواع-هي-الأسهل-في-الوقوع-بها&#34;&gt;ثلاثة فخاخ أنواع هي الأسهل في الوقوع بها
&lt;/h2&gt;&lt;h3 id=&#34;الفخ-1-غياب-نوع-boolean-الأصلي&#34;&gt;الفخ 1: غياب نوع Boolean الأصلي
&lt;/h3&gt;&lt;p&gt;لا تحتوي &lt;code&gt;SQLite&lt;/code&gt; على &lt;strong&gt;نوع boolean أصلي&lt;/strong&gt;. يمكن تمثيل قيمتي &lt;code&gt;True&lt;/code&gt; و &lt;code&gt;False&lt;/code&gt; بالأعداد الصحيحة &lt;code&gt;1&lt;/code&gt; و &lt;code&gt;0&lt;/code&gt; فقط.&lt;/p&gt;
&lt;p&gt;عندما تسترجع البيانات من &lt;code&gt;SQLite&lt;/code&gt; باستخدام &lt;code&gt;Node.js&lt;/code&gt;، ستحصل على الرقم &lt;code&gt;1&lt;/code&gt; أو &lt;code&gt;0&lt;/code&gt; وليس &lt;code&gt;true&lt;/code&gt; أو &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;إذا قمت مباشرة بإجراء فحص مثل &lt;code&gt;if (user.is_admin === true)&lt;/code&gt;، فلن يكون صحيحًا أبدًا.&lt;/p&gt;
&lt;h3 id=&#34;الفخ-2-غياب-نوع-datetime&#34;&gt;الفخ 2: غياب نوع Date/Time
&lt;/h3&gt;&lt;p&gt;لا تحتوي &lt;code&gt;SQLite&lt;/code&gt; على &lt;strong&gt;نوع للتاريخ/الوقت&lt;/strong&gt;. لا يمكنك تخزين الوقت إلا بالطرق التالية:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;طريقة التخزين&lt;/th&gt;
          &lt;th&gt;مثال&lt;/th&gt;
          &lt;th&gt;الميزات والعيوب&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;TEXT (سلسلة ISO-8601)&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;&#39;2026-05-19T18:00:00Z&#39;&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;الأكثر توصية&lt;/strong&gt;، وضوح عالٍ، وتحويل سلس عند الانتقال إلى PostgreSQL مستقبلاً&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;INTEGER (طابع Unix الزمني)&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;1747656000&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;يشغل مساحة صغيرة، ولكنه غير مقروء للبشر&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;لا تخزن التواريخ مطلقًا بتنسيقات مخصصة عشوائية مثل &lt;code&gt;19/5/2026 6:00 مساءً&lt;/code&gt;، وإلا فسيكون ترحيل البيانات مستقبلاً كارثة حقيقية.&lt;/p&gt;
&lt;h3 id=&#34;الفخ-3-إدخال-سلسلة-نصية-في-عمود-integer-لن-يؤدي-لحدوث-خطأ&#34;&gt;الفخ 3: إدخال سلسلة نصية في عمود INTEGER لن يؤدي لحدوث خطأ
&lt;/h3&gt;&lt;p&gt;في &lt;code&gt;PostgreSQL&lt;/code&gt; يؤدي إدخال سلسلة نصية في عمود &lt;code&gt;INTEGER&lt;/code&gt; إلى حدوث خطأ على الفور. ولكن &lt;code&gt;SQLite&lt;/code&gt; ستحاول التحويل بصمت فقط، وعند الفشل، ستقبل البيانات كما هي.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;هذا يعني أن &lt;strong&gt;البيانات الملوثة قد تتسلل بصمت إلى قاعدة بياناتك&lt;/strong&gt; حتى يأتي يوم يتوقف فيه برنامجك فجأة بسبب تلقي نوع غير متوقع، وعندها فقط تكتشف المشكلة.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;البرمجة-الدفاعية-مواجهة-قاعدة-بيانات-عفوية-بموقف-صارم&#34;&gt;البرمجة الدفاعية: مواجهة قاعدة بيانات عفوية بموقف صارم
&lt;/h2&gt;&lt;p&gt;في مواجهة عفوية وسهولة &lt;code&gt;SQLite&lt;/code&gt;، يجب عليك بناء &lt;strong&gt;آليات دفاع صارمة&lt;/strong&gt; في تطوير تطبيقات &lt;code&gt;Node.js&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;مستوى الدفاع&lt;/th&gt;
          &lt;th&gt;الأداة&lt;/th&gt;
          &lt;th&gt;الدور&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;حارس وقت الترجمة&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;التقاط الأنواع غير الصحيحة في مرحلة كتابة الكود&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;التحقق من مدخلات API&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Zod&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;التحقق من صحة البيانات الواردة بصرامة (ضمان أن يكون age رقمًا دائمًا)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;تحويل الأنواع الداخلي&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;Prisma / Drizzle ORM&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;معالجة فروق الأنواع تلقائيًا بين SQLite و PostgreSQL&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;إن نقل &lt;strong&gt;&amp;quot;حارس بوابة التحقق من البيانات&amp;quot;&lt;/strong&gt; من مستوى قاعدة البيانات إلى مستوى تطبيق &lt;code&gt;Node.js&lt;/code&gt; هو استراتيجية رئيسية للاستفادة من سرعة تطوير SQLite مع ضمان قابلية التوسع مستقبلاً.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;عند استخدام ORM، طالما أنك تعلن عن &lt;code&gt;type: &#39;boolean&#39;&lt;/code&gt; في كودك، فإن الـ ORM يقوم تلقائيًا بتحويله إلى &lt;code&gt;1/0&lt;/code&gt; عند الحفظ في &lt;code&gt;SQLite&lt;/code&gt; ويحوله مجددًا إلى &lt;code&gt;true/false&lt;/code&gt; عند القراءة، مما يخفي فروق الأنواع الأساسية تمامًا.&lt;/p&gt;
&lt;!--adsense--&gt;
&lt;h2 id=&#34;alter-table-غير-مكتمل-ما-يمكن-وما-لا-يمكن-تعديله&#34;&gt;ALTER TABLE غير مكتمل: ما يمكن وما لا يمكن تعديله
&lt;/h2&gt;&lt;p&gt;دعم &lt;code&gt;SQLite&lt;/code&gt; لتعديل بنية الجداول محدود للغاية:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;العملية&lt;/th&gt;
          &lt;th&gt;مدعومة&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;إضافة عمود (&lt;code&gt;ADD COLUMN&lt;/code&gt;)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;نعم&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;إعادة تسمية عمود (&lt;code&gt;RENAME COLUMN&lt;/code&gt;)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;نعم&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;حذف عمود (&lt;code&gt;DROP COLUMN&lt;/code&gt;)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;نعم&lt;/strong&gt; (في الإصدارات الحديثة)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;إعادة تسمية جدول (&lt;code&gt;RENAME TO&lt;/code&gt;)&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;نعم&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;تغيير نوع العمود&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;لا&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;إضافة/إزالة قيود &lt;code&gt;UNIQUE&lt;/code&gt; و &lt;code&gt;NOT NULL&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;لا&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;تعديل المفتاح الأساسي&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;لا&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;تعديل المفتاح الأجنبي&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;لا&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;بمجرد أن تحتاج إلى إجراء أي من التعديلات &amp;quot;غير المدعومة&amp;quot;، تتطلب منك &lt;code&gt;SQLite&lt;/code&gt; تنفيذ استراتيجية &lt;strong&gt;&amp;quot;إعادة الإنشاء والنقل&amp;quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;أربع-خطوات-لإعادة-الإنشاء-والنقل-طريقة-ترقية-جداول-sqlite&#34;&gt;أربع خطوات لإعادة الإنشاء والنقل: طريقة ترقية جداول SQLite
&lt;/h2&gt;&lt;p&gt;نظرًا لعدم إمكانية التعديل المباشر، فإن الطريقة القياسية الموصى بها في الوثائق الرسمية هي &lt;strong&gt;بناء منزل جديد، ونقل الأثاث، وتفجير المنزل القديم، وتعليق اللوحة الجديدة&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;الخطوة&lt;/th&gt;
          &lt;th&gt;الإجراء&lt;/th&gt;
          &lt;th&gt;الوصف&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;1&lt;/td&gt;
          &lt;td&gt;إنشاء جدول جديد&lt;/td&gt;
          &lt;td&gt;إنشاء &lt;code&gt;CREATE TABLE users_new (...)&lt;/code&gt; بالبنية الصحيحة&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;2&lt;/td&gt;
          &lt;td&gt;نسخ البيانات&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;INSERT INTO users_new SELECT ... FROM users&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;3&lt;/td&gt;
          &lt;td&gt;حذف الجدول القديم&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;DROP TABLE users&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;4&lt;/td&gt;
          &lt;td&gt;إعادة تسمية الجدول&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;ALTER TABLE users_new RENAME TO users&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;يجب تنفيذ هذه الخطوات الأربع &lt;strong&gt;دفعة واحدة ومن دون انقطاع&lt;/strong&gt;؛ أي انقطاع في الطاقة أو تعطل للتطبيق في منتصف الطريق سيؤدي إلى فقدان البيانات.&lt;/p&gt;
&lt;!--adsense--&gt;
&lt;h2 id=&#34;ضمان-عدم-فقدان-البيانات-أثناء-الترقية-خطان-للدفاع-عن-الأمان&#34;&gt;ضمان عدم فقدان البيانات أثناء الترقية: خطان للدفاع عن الأمان
&lt;/h2&gt;&lt;h3 id=&#34;خط-الدفاع-1-الدفاع-المادي-نسخ-الملف-مباشرة&#34;&gt;خط الدفاع 1: الدفاع المادي، نسخ الملف مباشرة
&lt;/h3&gt;&lt;p&gt;تعتبر &lt;code&gt;SQLite&lt;/code&gt; في جوهرها مجرد ملف واحد. قبل تنفيذ أي تغييرات في المخطط، يكفي ببساطة نسخ ملف &lt;code&gt;.db&lt;/code&gt; ليكون نسخة احتياطية.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;fs&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;copyFileSync&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;my_project.db&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;my_project_backup.db&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;إذا سارت الأمور بشكل سيء، فإن استبدال الملف يستعيد كل شيء في لمحة بصر. هذه ميزة لا توفرها قواعد البيانات الكبيرة الأخرى.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;خط-الدفاع-2-تغليف-المعاملة-transaction-آلة-الزمن-لقاعدة-البيانات&#34;&gt;خط الدفاع 2: تغليف المعاملة (Transaction), آلة الزمن لقاعدة البيانات
&lt;/h3&gt;&lt;p&gt;قم بتغليف جميع خطوات الترحيل داخل معاملة &lt;code&gt;Transaction&lt;/code&gt; واحدة؛ وإذا فشلت أي خطوة، فسيتم &lt;strong&gt;التراجع تلقائيًا (Rollback)&lt;/strong&gt; عن العملية بأكملها وكأن شيئًا لم يكن.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Database&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;better-sqlite3&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Database&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;my_project.db&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;migrateData&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;transaction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;prepare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;    CREATE TABLE users_new (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;      id INTEGER PRIMARY KEY AUTOINCREMENT,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;      name TEXT NOT NULL,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;      age INTEGER NOT NULL DEFAULT 18
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;  `&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;prepare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;    INSERT INTO users_new (id, name, age)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;    SELECT id, name, COALESCE(age, 18) FROM users
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;sb&#34;&gt;  `&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;prepare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;DROP TABLE users&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;db&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;prepare&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ALTER TABLE users_new RENAME TO users&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;try&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;migrateData&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;اكتملت ترقية الجدول&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;فشلت الترقية، تم استعادة البيانات بأمان:&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;ملف النسخ الاحتياطي + ربط المعاملة&amp;quot;&lt;/strong&gt; هو الوسادة الهوائية لترحيل قاعدة بياناتك.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;التحكم-في-عفوية-sqlite-بموقف-صارم&#34;&gt;التحكم في عفوية SQLite بموقف صارم
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;تحكم في عفوية وسهولة &lt;code&gt;SQLite&lt;/code&gt; باستخدام &lt;strong&gt;بنية صارمة لطبقة التطبيق&lt;/strong&gt; للاستمتاع بميزة سرعة التطوير الفائقة مع تجنب الديون التقنية مستقبلاً.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;يعتبر نظام الأنواع في SQLite مرنًا وعفويًا للغاية، كما أن &lt;code&gt;ALTER TABLE&lt;/code&gt; لديه العديد من القيود.&lt;/p&gt;
&lt;p&gt;ولكن طالما أنك تقوم بتطبيق &lt;strong&gt;فحص أنواع TypeScript + تحقق Zod + تجريد الـ ORM&lt;/strong&gt; في جهة &lt;code&gt;Node.js&lt;/code&gt; بجدية، وتدمج ذلك مع استراتيجية الأمان المتمثلة في &lt;strong&gt;النسخ الاحتياطي المادي + المعاملات الصارمة&lt;/strong&gt;، فيمكنك الاستمتاع بكفاءة التطوير الرائعة التي توفرها &lt;code&gt;SQLite&lt;/code&gt; مع تمهيد الطريق للانتقال السلس إلى &lt;code&gt;PostgreSQL&lt;/code&gt; مستقبلاً.&lt;/p&gt;
&lt;!--adsense--&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://sqlite.org/datatype3.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Datatypes In SQLite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.runoob.com/sqlite/sqlite-data-types.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;SQLite 数据类型 | 菜鸟教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.sqlite.org/lang_transaction.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Transaction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://sqlite.org/lang.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Query Language Understood by SQLite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/SQLite&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;SQLite - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        
    </channel>
</rss>
