Explicar el funcionamiento de transaction.atomic()

publicado por: Anonymous

Estoy empezando un proyecto en django y mirando ejemplos veo que usan transaction.atomic() para guardar en la base de datos pero no comprendo exactamente el funcionamiento.

solución

Intentaré explicarlo con un ejemplo.

Imagina que tienes una clase cuenta donde vamos a almacenar un importe. Algo así:

from django.db import models
from django.contrib.auth.models import User


class Cuenta(models.Model):
    id = models.AutoField(
        primary_key=True,
    )
    user = models.ForeignKey(
        User,
    )
    importe_total = models.IntegerField(
        default=0,
    )

Ahora queremos tanto sacar dinero como guardarlo:

def guardar_dinero(self, cantidad):
    self.importe_total += cantidad
    self.save()

def sacar_dinero(self, cantidad):
    if cantidad > self.balance:
        raise errors.InsufficientFunds()
    self.importe_total -= cantidad
    self.save()

Son dos ejemplos muy sencillos que si estamos trabajando con una gran cantidad de operaciones que podrían darse a la vez tanto la opción de sacar como de guardar pues tendríamos un gran problema. Lo explico:

  • Usuario A y B comparten una cuenta con un importe de 100€. A la vez realizan una operación diferente cada uno.

  • Usuario B saca 30€  => actualizamos el importe => 100€  –  30$ = 70€.

  • Usuario A guarda 50€ => actualizamos el importe => 100€ + 50€ = 0150€.

Si te fijas el saldo final en la cuenta es de 150€ cuando debería ser de 120€.

¿Por qué pasa esto? Pues porque cuando realizan la operación el importe en la cuenta es de 100€ para los dos, su operación la hacen sobre este importe, por lo tanto, al final tendrá un saldo extra de 30€.

Con atomic bloquea la segunda operación (guardar) hasta que la primera no termina (sacar) así la segunda operación contará con el valor de 70€ en lugar de 100€. Te recomiendo leer la “Pessimistic approach” del artículo de medium que te menciono más abajo para que tengas una ejemplo completo de como usarlo, no lo expongo aquí puesto que solamente preguntas por qué es atomic no por como usarlo.

Si no vas a tener un volumen de consultas grande o no vas a usar datos delicados, como podría ser el dinero, no te recomendaría usarlo porque ralentiza mucho las operaciones.

Te dejo un enlace a la documentación oficial de Django así como el artículo de medium que consulté para obtener esta información y que te recomiendo.

Además cuidado con las tablas relacionadas, si quieres interactuar con un campo que tenga una relación (ForeignKey, etc.) cuidado porque atomic bloquea las dos tablas haciendo que la tabla relacional tampoco se pueda usar. En la documentación de Django tienes un ejemplo con un select_for_update() debería funcionar.

También te dejo un ejemplo completo de como manejar una cuenta bancaria.

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *