Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

200
Vistas
¿Por qué select_for_update funciona en inserciones simultáneas?

Tengo un código que debería funcionar bajo una solicitud simultánea y una carga pesada.

Escribí un ejemplo para dar una mejor comprensión de lo que estoy tratando de hacer:

 def add_tag(): with transaction.atomic(): image = Image.objects.get(pk=2) tag = Tag.objects.get(pk=6) image.tags.add(tag) # concurrent insert return 'done' class Command(BaseCommand): def handle(self, *args, **options): with ProcessPoolExecutor(max_workers=3) as executor: futures = [] for _ in range(3): futures.append(executor.submit(add_tag)) for future in as_completed(futures): print(future.result())

Y aquí están mis modelos:

 class Image(models.Model): title = models.CharField(max_length=255) tags = models.ManyToManyField('ov_tags.Tag') class Tag(models.Model): title = models.CharField(max_length=255)

Estoy tratando de insertar en la tabla de relaciones ManyToMany en paralelo. Obviamente, esto provoca un error, debido al nivel de aislamiento de LECTURA COMPROMETIDA:

 django.db.utils.IntegrityError: duplicate key value violates unique constraint

Absolutamente bien, pero ¿cómo eliminar este error por completo?

Para proteger mi imagen, traté de usar select_for_update en la selección de imagen.

 image = Image.objects.select_for_update().get(pk=2)

¡Y funciona! Lo ejecuto varias veces. Ya no hay errores y el artículo se insertó correctamente. Pero no sé por qué?

¿Está select_for_update bloqueando la tabla relacional de todos modos? ¿O está sucediendo en un lado de la aplicación? ¿Hay una manera correcta de lograr tal comportamiento?

¿Puedo usar la selección vacía para bloquear para insertar?

 SELECT "image_tags"."tag_id" FROM "image_tags" WHERE ("image_tags"."tag_id" IN (6) AND "image_tags"."image_id" = 2) FOR UPDATE
over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

A nivel de base de datos, solo está bloqueando la instancia de Image específica a la que está agregando etiquetas. Tiene razón en que esto no impide las inserciones en la tabla relacional. Si otra pieza de código ignora el bloqueo y simplemente inserta una nueva fila en la tabla de relaciones, aún puede tener problemas.

Funciona para este fragmento de código porque cada transacción tiene un "buen comportamiento". Cada transacción primero adquiere un bloqueo en la imagen específica, antes de agregar nuevas entradas a la tabla relacional. Esto significa que cada proceso en el grupo de ejecutores esperará a que el proceso actual termine su transacción antes de intentar agregar nuevas filas en la tabla relacional.

Esto también funcionaría si bloqueara la Tag en lugar de la Image , pero no funciona si algún código bloquea la Tag , mientras que otro código bloquea la Image . En ese momento, un proceso puede adquirir el bloqueo en Image , pero el otro proceso no espera porque aún puede adquirir el bloqueo en Tag , y ambos procesos intentan insertar la misma fila en la tabla relacional al mismo tiempo. .

Eso es lo que quiero decir con "buen comportamiento": cada parte de su aplicación debe comportarse de una manera específica (adquirir el mismo bloqueo). Si solo una parte de su aplicación ignora este requisito, puede encontrarse con condiciones de carrera. Solo si todas las partes de su aplicación se comportan bien, podrá evitar las condiciones de carrera de esta manera.

over 4 years ago · Santiago Trujillo Denunciar

0

Esto es exactamente lo que está sucediendo, la llamada select_for_update está bloqueando la tabla de imágenes en el nivel de la base de datos, de modo que ninguna otra transacción podrá modificar las filas seleccionadas hasta el final del bloque transaction.atomic .

Ver para referencia https://docs.djangoproject.com/en/1.11/ref/models/querysets/#select-for-update

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda