إلى AppEngine: الحفاظ على مخزن البيانات الثبات عند إنشاء السجلات
-
22-08-2019 - |
سؤال
ولقد ضرب معضلة صغيرة! لدي معالج يسمى التصويت. عندما يتم استدعاء انها تضع تصويت المستخدم إلى كل ما اخترته. لنتذكر ما الخيارات التي التقطت من قبل، وأنا تخزين خيارات VoteRecord الذي تفاصيل ما تم تعيين تصويتهم الحالي.
وبطبيعة الحال، فإن المرة الأولى التي التصويت، لا بد لي من إنشاء كائن وتخزينه. لكن الأصوات المتعاقبة ينبغي أن مجرد تغيير قيمة VoteRecord القائمة. لكنه يأتي المشكلة: في بعض الظروف يمكن إنشاء اثنين VoteRecords. انها نادرة (حدث مرة واحدة فقط في كل 500 صوت رأيناه حتى الآن)، ولكن لا يزال سيئا عندما تفعل ذلك.
وكانت المشكلة تحدث لأن اثنين من معالجات منفصلة كلا تفعل أساسا هذا:
query = VoteRecord.all().filter('user =', session.user).filter('poll =', poll)
if query.count(1) > 0:
vote = query[0]
poll.votes[vote.option] -= 1
poll.votes[option] += 1
poll.put()
vote.option = option
vote.updated = datetime.now()
vote.put()
else:
vote = VoteRecord()
vote.user = session.user
vote.poll = poll
vote.option = option
vote.put()
poll.votes[option] += 1
poll.put()
session.user.votes += 1
session.user.xp += 3
session.user.put()
incr('votes')
وسؤالي هو: ما هو الأكثر فعالية وأسرع طريقة للتعامل مع هذه الطلبات مع ضمان أن أي طلب يتم فقدان وأي طلب يخلق كائنين VoteRecord
المحلول
والمسألة هي هذا الجزء:
if vote.count(1) == 0:
obj = VoteRecord()
obj.user = user
obj.option = option
obj.put()
وبدون معاملة، يمكن تشغيل التعليمات البرمجية في هذا النظام في حالتين مترجم:
if vote.count(1) == 0:
obj = VoteRecord()
obj.user = user
if vote.count(1) == 0:
obj = VoteRecord()
obj.user = user
obj.option = option
obj.put()
obj.option = option
obj.put()
وأو أي مزيج غريب منه. المشكلة هي اختبار العد يعمل مرة أخرى قبل أن حدث وضعت، وبالتالي فإن موضوع الثاني يمر عبر الجزء الأول من الشرطي بدلا من الثانية.
ويمكنك تصحيح هذا عن طريق وضع التعليمات البرمجية في وظيفة ثم استخدام
db.run_in_transaction()
لتشغيل وظيفة.
والمشكلة هي يبدو لك أن تكون بالاعتماد على عدد من الأشياء التي أرجعها استعلام عن منطق القرار الخاص التي تحتاج إلى أن توضع في الصفقة. إذا كنت تقرأ المحادثات جوجل I / O أو إلقاء نظرة على مجموعة سترى أن هذا غير مستحسن. هذا لأنك لا يمكن transactionalize استعلام. بدلا من ذلك، يجب تخزين عدد كقيمة كيان في مكان ما، الاستعلام عن ذلك خارج م> وظيفة الصفقة، ومن ثم تمرير مفتاح لهذا الكيان إلى وظيفة معاملتك.
وهنا مثال على وظيفة المعاملات التي يتحقق خاصية الكيان. لقد مرت على مفتاح كمعلمة:
def checkAndLockPage(pageKey):
page = db.get(pageKey)
if page.locked:
return False
else:
page.locked = True
page.put()
return True
ويمكن لمستخدم واحد فقط في وقت قفل هذا الكيان، وسوف يكون هناك أبدا أي أقفال مكررة.
نصائح أخرى
وأسهل طريقة للقيام بذلك هو استخدام أسماء الرئيسية للكائنات صوتك، واستخدام Model.get_or_insert. أولا، وتأتي مع نظام تسمية أسماء الرئيسية الخاصة بك - تسميتها بعد الانتخابات هو فكرة جيدة - ومن ثم القيام get_or_insert لجلب أو إنشاء كيان ذات الصلة:
vote = VoteRecord.get_or_insert(pollname, parent=session.user, user=session.user, poll=poll, option=option)
if vote.option != option:
# Record already existed; we need to update it
vote.option = option
vote.put()