Realm هو أفضل حل لقاعدة بيانات Android

نشرت: 2022-03-11

منذ إنشاء Android ، نستخدم نحن مطورو التطبيقات SQLite لتخزين بياناتنا المحلية. في بعض الأحيان باستخدام عبارات SQL مباشرة ، وأحيانًا باستخدام مخطط العلاقة بين الكائنات (ORM) كطبقة تجريد ، ولكن في كلتا الحالتين ، كنا نستخدم SQLite في نهاية اليوم.

على الرغم من جميع مزايا SQLite ، على الرغم من ذلك ، كانت هناك أوقات كنا نتمنى أن يكون لدينا فيها بدائل للنموذج العلائقي: شيء يمكن أن يمنعنا من الاضطرار إلى إضافة رمز معياري لتحويل القيم من قاعدة البيانات وإليها ، أو تمكيننا من تخطي إعداد التعيينات بين الفئات والجداول والحقول والأعمدة والمفاتيح الخارجية وما إلى ذلك.

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

هذه ، في الواقع ، بعض الفوائد الجاهزة التي نحصل عليها مع Realm ، منصة قاعدة بيانات ذات بنية مميزة ، والتي ظهرت كبديل جديد لـ SQLite.

تقدم هذه المقالة بعض الأسباب الرئيسية التي جعلت Realm قد استحوذ على الكثير من الاهتمام ولماذا قد ترغب في التفكير في تجربته. يناقش بعض المزايا الرئيسية التي توفرها Realm لمطوري Android عبر SQLite.

نظرًا لأن Realm متاح على منصات متعددة ، فإن بعض ما سيتم تناوله في هذه المقالة له صلة بمنصات الهواتف المحمولة الأخرى أيضًا ، مثل iOS و Xamarin و React Native.

سكليتي: إنها تعمل ، لكنها ليست ما تحتاجه في معظم الأوقات

ربما يكون معظم مطوري الأجهزة المحمولة على دراية بـ SQLite. لقد كان موجودًا منذ عام 2000 ، ويمكن القول إنه محرك قاعدة البيانات العلائقية الأكثر استخدامًا في العالم.

تمتلك SQLite عددًا من الفوائد التي ندركها جميعًا ، من بينها دعمها الأصلي على Android.

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

ومع ذلك ، فإن التعامل المباشر مع عبارات SQL له عدد من الجوانب السلبية.

وفقًا لوثائق Android الرسمية ، إليك الخطوات اللازمة لبدء القراءة / الكتابة إلى SQLite:

  1. صف مخططك من حيث فئات العقد.
  2. حدد أوامر إنشاء / إسقاط الجدول في سلاسل.
  3. قم بتوسيع SQLiteOpenHelper لتشغيل أوامر الإنشاء وإدارة الترقيات / التخفيضات.

بمجرد القيام بذلك ، ستكون جاهزًا للقراءة والكتابة في قاعدة البيانات الخاصة بك. ومع ذلك ، سوف تحتاج إلى التحويل ذهابًا وإيابًا بين العناصر في تطبيقك والقيم في قاعدة البيانات. قصة قصيرة طويلة: إنها الكثير من التعليمات البرمجية المعيارية!

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

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

مخطط العلاقة بين الكائنات: أداة المساعدة لتحديات SQL

لإنقاذنا من التعامل مع SQL الخام ، جاءت ORMs لإنقاذنا.

بعض أشهر أنظمة تشغيل نظام التشغيل Android هي DBFlow و greenDAO و OrmLite.

أعظم قيمة يجلبونها هي تجريد SQLite ، مما يتيح لنا تعيين كيانات قاعدة البيانات إلى كائنات Java بسهولة نسبيًا.

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

على الرغم من حقيقة أن أدوات ORM هذه قد رفعت مستوى قواعد بيانات Android ، إلا أن لها عيوبها أيضًا. في كثير من الحالات ، ينتهي بك الأمر بتحميل بيانات غير ضرورية.

هنا مثال.

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

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

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

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

المملكة: بديل مثالي

Realm Mobile Database هي قاعدة بيانات مصممة للأجهزة المحمولة من الألف إلى الياء.

يتمثل الاختلاف الرئيسي بين Realm و ORMs في أن Realm ليس تجريدًا مبنيًا على قمة SQLite ، ولكنه محرك قاعدة بيانات جديد تمامًا. بدلاً من النموذج العلائقي ، فهو يعتمد على مخزن العناصر. يتكون جوهرها من مكتبة C ++ قائمة بذاتها. وهو يدعم حاليًا Android و iOS (Objective-C و Swift) و Xamarin و React Native.

تم إطلاق Realm في يونيو 2014 ، لذا يبلغ عمرها حاليًا عامين ونصف (جديد جدًا!).

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

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

النمذجة سهلة

فيما يلي مثال لبعض النماذج التي تم إنشاؤها باستخدام Realm:

 public class Contact extends RealmObject { @PrimaryKey String id; protected String name; String email; @Ignore public int sessionId; //Relationships private Address address; private RealmList<Contact> friends; //getters & setter left out for brevity }
 public class Address extends RealmObject { @PrimaryKey public Long id; public String name; public String address; public String city; public String state; public long phone; }

تمتد نماذجك من RealmObject. يقبل Realm جميع الأنواع الأولية وأنواعها المعبأة (باستثناء char ) String Date byte[] . كما أنه يدعم الفئات الفرعية لـ RealmObject و RealmList<? extends RealmObject> RealmList<? extends RealmObject> لنمذجة العلاقات.

يمكن أن تحتوي الحقول على أي مستوى وصول (خاص ، عام ، محمي ، إلخ). يتم الاحتفاظ بجميع الحقول افتراضيًا ، وتحتاج فقط إلى إضافة تعليق توضيحي على الحقول "الخاصة" (على سبيل المثال ، @PrimaryKey لحقل المفتاح الأساسي ، @Ignore لتعيين الحقول غير الدائمة ، وما إلى ذلك).

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

العلاقات

عندما يتعلق الأمر بالعلاقات ، هناك خياران:

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

  • أضف RealmList للنماذج التي يتم الرجوع إليها. تتصرف RealmLists تمامًا مثل Lists Java القديمة الجيدة ، حيث تعمل كحاوية لكائنات Realm. يمكننا أن نرى أن نموذج جهات Contact لدينا يحتوي على RealmList من جهات الاتصال ، وهم أصدقائها في هذا المثال. يمكن تصميم علاقات رأس بأطراف ومتعدد بأطراف باستخدام هذا الأسلوب.

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

تحذير: لا يوجد دعم لميراث النموذج. الحل الحالي هو استخدام التركيب. لذلك ، على سبيل المثال ، إذا كان لديك نموذج Animal وكنت تأمل في إنشاء نموذج Dog يمتد من Animal ، فسيتعين عليك بدلاً من ذلك إضافة مثيل Animal كحقل في Dog . هناك جدل كبير حول التكوين مقابل الميراث. إذا كنت تريد استخدام الميراث ، فهذا بالتأكيد شيء تحتاج إلى معرفته عن المملكة. باستخدام SQLite ، يمكن تنفيذ ذلك باستخدام جدولين (أحدهما للوالد والآخر للطفل) متصلين بواسطة مفتاح خارجي. بعض ORMs أيضًا لا تفرض هذا التقييد ، مثل DBFlow.

استرجع البيانات التي تحتاجها فقط! تصميم نسخة صفرية

هذه ميزة قاتلة.

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

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

نتيجة لذلك ، تكون الاستعلامات سريعة للغاية (انظر هنا وهنا للحصول على بعض النتائج المعيارية).

هذه ميزة كبيرة على ORMs التي عادةً ما تقوم بتحميل جميع البيانات من صفوف SQL المحددة مقدمًا.

يصبح تحميل الشاشة أكثر فاعلية نتيجة لذلك دون الحاجة إلى أي جهد إضافي من المطور: إنه مجرد سلوك افتراضي لشركة Realm.

بالإضافة إلى ذلك ، هذا يعني أيضًا أن التطبيقات تستهلك ذاكرة أقل ، وبالنظر إلى أننا نتحدث عن بيئة محدودة الموارد مثل الأجهزة المحمولة ، يمكن أن يحدث فرقًا كبيرًا.

نتيجة أخرى لنهج النسخة الصفرية هي أن الكائنات التي يديرها Realm يتم تحديثها تلقائيًا.

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

رسم توضيحي: الحصول على بيانات العالم من كائنات وخيوط متعددة.

إذا كنت قد قرأت بالفعل بيانات من كائنات Realm وعرضتها على الشاشة ، على سبيل المثال ، وتريد تلقي تحديثات عندما تتغير البيانات الأساسية ، يمكنك إضافة مستمع:

 final RealmResults<Contact> johns = realm.where(Contact.class).beginsWith("name", "John ").findAll(); johns.addChangeListener(new RealmChangeListener<RealmResults<Contact>>() { @Override public void onChange(RealmResults<Contact> results) { // UPDATE UI } });

انها ليست مجرد غلاف

على الرغم من أن لدينا العشرات من الخيارات لـ ORMs ، إلا أنها عبارة عن أغلفة ، وكل ذلك يعود إلى SQLite في الأسفل ، مما يحد من المدى الذي يمكنهم الوصول إليه. في المقابل ، فإن Realm ليس مجرد غلاف SQLite آخر. لديها الحرية في تقديم ميزات لا تستطيع إدارة ORM تقديمها.

تتمثل إحدى التغييرات الأساسية في Realm في القدرة على تخزين البيانات كمخزن للرسم البياني للكائن.

هذا يعني أن Realm هي كائنات على طول الطريق ، من مستوى لغة البرمجة إلى قاعدة البيانات. وبالتالي ، هناك الكثير من التحويل الذي يتم إجراؤه ذهابًا وإيابًا أثناء كتابة القيم وقراءتها ، مقارنةً بقاعدة البيانات العلائقية.

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

إذا فكرنا في مكونات في بنية Realm ، في الجزء السفلي يوجد جوهرها مع التنفيذ الأساسي للنظام الأساسي. علاوة على ذلك ، سيكون لدينا مكتبات ملزمة لكل نظام أساسي مدعوم.

رسم توضيحي: هندسة العالم من المركز إلى المكتبات المختلفة.

عند استخدام غلاف لبعض التقنيات التي لا تتحكم فيها ، ستحتاج في النهاية إلى توفير نوع من طبقة التجريد حوله.

صُممت أضلاع ربط المجال لتكون رفيعة قدر الإمكان ، للتخلص من تعقيد التجريد. إنهم ينشرون في الغالب فكرة التصميم من Core. من خلال التحكم في البنية بالكامل ، تعمل هذه المكونات بشكل أفضل مع بعضها البعض.

أحد الأمثلة العملية هو الوصول إلى كائنات مرجعية أخرى (مفاتيح خارجية في SQL). تعتمد بنية ملفات Realm على الروابط الأصلية ، لذلك عندما تقوم بالاستعلام عن العلاقات ، بدلاً من الاضطرار إلى ترجمة تجريد ORM إلى جداول علائقية و / أو الانضمام إلى جداول متعددة ، تحصل على روابط أولية للكائنات على مستوى نظام الملفات في تنسيق الملف.

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

المجتمع والدعم

Realm قيد التطوير النشط وقد تم إصدار إصدارات محدثة في كثير من الأحيان.

جميع المكونات من Realm Mobile Database مفتوحة المصدر. إنهم مستجيبون للغاية فيما يتعلق بتتبع المشكلات و Stack Overflow ، لذلك يمكنك توقع دعم جيد وسريع على هذه القنوات.

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

بدأت في استخدام Realm في عام 2015 ، ومنذ ذلك الحين ، صادفت العديد من المنشورات على الويب بآراء مختلفة حول Realm. سنتحدث عن حدوده قريبًا ، ولكن هناك شيء واحد لاحظته وهو أن العديد من الشكاوى المقدمة في وقت النشر قد تم إصلاحها منذ ذلك الحين.

عندما تعرفت على Realm ، على سبيل المثال ، لم يكن هناك دعم حتى الآن للطرق المخصصة على الطرز والمكالمات غير المتزامنة. كانت هذه بمثابة كسر للصفقة بالنسبة للكثيرين في ذلك الوقت ، ولكن كلاهما مدعوم حاليًا.

تجعلنا سرعة التطوير والاستجابة هذه أكثر ثقة بأننا لن ننتظر طويلاً للحصول على ميزات مهمة.

محددات

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

  • على الرغم من أنه من الممكن أن يكون لديك العديد من سلاسل الرسائل للقراءة من قاعدة البيانات والكتابة إليها في نفس الوقت ، إلا أنه لا يمكن نقل كائنات Realm عبر سلاسل الرسائل. لذا ، على سبيل المثال ، إذا قمت باسترداد كائن مجال باستخدام doInBackground doInBackground() الخاص بـ AsyncTask ، والذي يتم تشغيله في سلسلة رسائل في الخلفية ، فلا يمكنك تمرير هذا المثيل إلى أساليب onPostExecute() ، نظرًا لأن تلك الطرق تعمل على مؤشر الترابط الرئيسي. قد تكون الحلول الممكنة لهذا الموقف إما عمل نسخة من الكائن وتمريرها أو تمرير معرف الكائن واسترداد الكائن مرة أخرى على onPostExecute() . يقدم Realm طرقًا متزامنة وغير متزامنة للقراءة / الكتابة.

  • لا يوجد دعم للمفاتيح الأساسية للزيادة التلقائية ، لذلك ستحتاج إلى التعامل مع إنشاء هذه المفاتيح بنفسك.

  • لا يمكن الوصول إلى قاعدة البيانات من عمليات مختلفة في نفس الوقت . وفقًا لوثائقهم ، سيتوفر دعم متعدد العمليات قريبًا.

العالم هو مستقبل حلول قواعد البيانات المتنقلة

يعد SQLite محرك قاعدة بيانات قويًا وقويًا وثابتًا ، ولن تختفي قواعد البيانات العلائقية في أي وقت قريبًا. هناك عدد من أدوات إدارة السجلات (ORMs) الجيدة التي ستفعل الحيلة للعديد من السيناريوهات أيضًا.

ومع ذلك ، من المهم مواكبة الاتجاهات الحالية.

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

تجلب Realm معها نهجًا فريدًا للتعامل مع البيانات ذات القيمة للمطورين ، ليس فقط لأنها يمكن أن تكون خيارًا أفضل من الحلول الحالية ، ولكن أيضًا لأنها توسع آفاقنا من حيث الاحتمالات الجديدة وترفع مستوى تكنولوجيا قواعد البيانات المتنقلة.

هل لديك بالفعل خبرة مع Realm؟ لا تتردد في مشاركة أفكارك.