سؤال

ولقد ضرب معضلة صغيرة! لدي معالج يسمى التصويت. عندما يتم استدعاء انها تضع تصويت المستخدم إلى كل ما اخترته. لنتذكر ما الخيارات التي التقطت من قبل، وأنا تخزين خيارات 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()
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top