6. Race Condition
Counter.objects.update(views= 1)
# Watęk A (w tym samym czasie)
# Watęk B (w tym samym czasie)
counter = Counter.objects.get(pk= 1)
counter = Counter.objects.get(pk= 1)
counter.views += 1
counter.save()
print Couter.objects.get(pk= 1).counter
>>> 2
counter.views += 1
counter.save()
7. SELECT … FOR UPDATE
print Counter.objects.update(views= 1)
# Watęk A
counter = Counter.objects.
select_for_update().get(pk= 1)
time.sleep( 100)
counter.views += 1
counter.save()
# Watęk B (+2 po Wątku B)
counter = Counter.objects.
select_for_update().get(pk= 1)
counter.views += 1
counter.save()
8. SELECT … FOR UPDATE
● select_for_update tylko gdy będzie update
● w django od wersji 1.4
● lub na podstawie snippeta https:
//djangosnippets.org/snippets/2766/ w
django < 1.4
9. Co jest nie tak z .save()
W pewnym frameworku podczas logowania…
# django/contrib/auth/models.py
def update_last_login(sender, user,
**kwargs):
user.last_login = timezone.now()
user.save()
UPDATE `auth_user` SET
`username` = %s, `first_name` =
%s, `last_name` = %s, `email` =
%s, `password` = %s, `is_staff`
= %s, `is_active` = %s,
`is_superuser` = %s,
`last_login` = %s, `date_joined`
= %s WHERE `auth_user`.`id` = %s
10. Dlaczego taki save jest zły ?
● brak kontroli nad tym co jest zapisywane do
bazy
● wydajność bazy danych
● nadpisywanie zmian (cudzych)
● utrudnia debugowanie - serio!
● django.admin :(
11. Model.save (the right way)
● Użycie save(update_fields=[..]) - trudne w
utrzymaniu!
● Użycie django-dirtyfields + własny save
● Własny update(field=val,..)
12. TransactionMiddleware (depercated)
It works like this: When a request starts, Django
starts a transaction. If the response is produced
without problems, Django commits any pending
transactions
docs.djangoproject.com