Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The issue is this part: </p> <pre><code>if vote.count(1) == 0: obj = VoteRecord() obj.user = user obj.option = option obj.put() </code></pre> <p>Without a transaction, your code could run in this order in two interpreter instances:</p> <pre><code>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() </code></pre> <p>Or any weird combination thereof. The problem is the count test runs again before the put has occured, so the second thread goes through the first part of the conditional instead of the second.</p> <p>You can fix this by putting the code in a function and then using</p> <pre><code>db.run_in_transaction() </code></pre> <p>to run the function.</p> <p>Problem is you seem to be relying on the count of objects returned by a query for your decision logic that needs to be put in the transaction. If you read the Google I/O talks or look at the group you'll see that this is not recommended. That's because you can't transactionalize a query. Instead, you should store the count as an entity value somewhere, query for it <em>outside</em> of the transaction function, and then pass the key for that entity to your transaction function.</p> <p>Here's an example of a transaction function that checks an entity property. It's passed the key as a parameter:</p> <pre><code>def checkAndLockPage(pageKey): page = db.get(pageKey) if page.locked: return False else: page.locked = True page.put() return True </code></pre> <p>Only one user at a time can lock this entity, and there will never be any duplicate locks.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload