توقع معرف الصف التالي الذي تم إدراجه تلقائيًا (SQLite)

StackOverflow https://stackoverflow.com/questions/107005

  •  01-07-2019
  •  | 
  •  

سؤال

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

هل توقع المعرف التالي بسيط مثل الحصول على المعرف الأخير وإضافة واحد؟هل هذا ضمان؟

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

هل كانت مفيدة؟

المحلول

إن إلغاء أو تنفيذ سلسلة من عمليات قاعدة البيانات مرة واحدة هو بالضبط الغرض من المعاملات.استفسار BEGIN; قبل أن يبدأ المستخدم في العبث و COMMIT; بمجرد الانتهاء من ذلك.نضمن لك إما تطبيق جميع التغييرات (إذا قمت بالالتزام) أو إلغاء كل شيء (إذا قمت بالاستعلام ROLLBACK;, ، إذا تعطل البرنامج، انقطعت الطاقة، وما إلى ذلك).بمجرد القراءة من قاعدة البيانات، نضمن أيضًا أن البيانات جيدة حتى نهاية المعاملة، حتى تتمكن من الحصول عليها MAX(id) أو ما تريد دون القلق بشأن ظروف السباق.

http://www.sqlite.org/lang_transaction.html

نصائح أخرى

يحاول SELECT * FROM SQLITE_SEQUENCE WHERE name='TABLE';.سيحتوي هذا على حقل يسمى seq وهو أكبر رقم للجدول المحدد.أضف 1 إلى هذه القيمة للحصول على المعرف التالي.

انظر أيضا مقالة التزايد التلقائي لـ SQLite, ، ومن هنا جاءت المعلومات المذكورة أعلاه.

هتافات!

ربما يمكنك التخلص من إضافة 1 إلى القيمة التي يتم إرجاعها بواسطة sqlite3_last_insert_rowid في ظل ظروف معينة، على سبيل المثال، باستخدام نفس اتصال قاعدة البيانات ولا يوجد كتاب متزامنون آخرون.بالطبع، يمكنك الرجوع إلى كود مصدر sqlite لدعم هذه الافتراضات.

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

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

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

يحرر: إذا استطعت، استخدم اقتراح Eevee لاستخدام المعاملات المناسبة.إنه عمل أقل بكثير.

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

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

في معظم البيئات، لا يمكنك افتراض أن البيانات التي تم استردادها عبر SELECT ضمن المعاملة قابلة للتكرار.على سبيل المثال

SELECT Balance FROM Bank ...
UPDATE Bank SET Balance = valuefromselect + 1.00 WHERE ...

بعد التحديث، قد تتغير قيمة الرصيد.في بعض الأحيان يمكنك التغلب على ذلك عن طريق تحديث الصف (الصفوف) الذي تهتم به في البنك أولاً ضمن المعاملة حيث يضمن ذلك قفل الصف ومنع المزيد من التحديثات من تغيير قيمته حتى اكتمال معاملتك.

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

WHERE Balance = valuefromselect

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

select max(id) from particular_table is unreliable for the reason below..

http://www.sqlite.org/autoinc.html

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

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

راجع للشغل لقد استخدمت MySQL فقط ولكن لا أعتقد أن ذلك سيحدث أي فرق)

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

حدد قيمة last_insert_rowid().

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

select max(id) from particular_table;

سيكون المعرف التالي هو +1 من الحد الأقصى للمعرف.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top