2010-07-09 15 views
5

Como los métodos de guardar de django modelo are not lazy, y como mantener las transacciones cortas es una buena práctica general, ¿deberían reservarse preferiblemente los ahorros al final de los bloques de transacción?Django - Guardar operaciones basadas en save() short

Como ejemplo, ¿la muestra de código B mantendría una transacción abierta por menos tiempo que la muestra de código A a continuación?

muestra

Código A:

from django.db import transaction 
from my_app.models import MyModel 

@transaction.commit_on_success 
def model_altering_method(): 
    for inst in MyModel.objects.all()[0:5000]: 
     inst.name = 'Joel Spolsky' 
     # Some models independent time consuming operations... 
     inst.save() 

Ejemplo de código B:

from django.db import transaction 
from my_app.models import MyModel 

@transaction.commit_on_success 
def model_altering_method(): 
    instances_to_save = [] 
    for inst in MyModel.objects.all()[0:5000]: 
     inst.name = 'Joel Spolsky' 
     # Some models independent time consuming operations... 
     instances_to_save.append(inst) 

    for inst in instances_to_save: 
     inst.save() 

Respuesta

1

El comportamiento predeterminado de Django es ejecutar con una transacción abierta que se confirma automáticamente cuando se llama a cualquier función de modelo incorporada que altere los datos. En el caso de commit_on_success o commit_manually decorators, django no confirma al guardar(), sino más bien al ejecutar la ejecución de la función con éxito o al comando transaction.commit(), respectivamente.

Por lo tanto, el enfoque elegante sería separar el código de gestión de transacciones y otros códigos que consume tiempo, si es posible:

from django.db import transaction 
from my_app.models import MyModel 

@transaction.commit_on_success 
def do_transaction(instances_to_save): 
    for inst in instances_to_save: 
     inst.save() 

def model_altering_method(): 
    instances_to_save = [] 
    for inst in MyModel.objects.all()[0:5000]: 
     inst.name = 'Joel Spolsky' 
     # Some models independent time consuming operations... 
     instances_to_save.append(inst) 
    do_transaction(instances_to_save) 

Si esto es imposible de diseño inteligente, por ejemplo, necesita información de instancia.id que para nuevas instancias solo puede obtener después del primer save(), intente dividir su flujo en unidades de trabajo de tamaño razonable, para no mantener la transacción abierta durante largos minutos.

También tenga en cuenta que tener transacciones largas no siempre es malo. Si su aplicación es la única entidad que modifica el DB, en realidad podría estar bien. Sin embargo, debe verificar la configuración específica de su db para ver el límite de tiempo para las transacciones (o transacción inactiva).

3

No estoy seguro, pero aquí está mi teoría - Me gustaría pensar que su decorador commit_manually comenzará una nueva transacción en lugar de tener una nueva transacción que surge cuando haces tu primer guardado. Entonces mi teoría es que la muestra de código B mantendría la transacción abierta por más tiempo, ya que tiene que recorrer dos veces la lista de modelos.

De nuevo, eso es solo una teoría, y también podría depender de qué DBMS esté utilizando en cuanto a cuándo se inicia la transacción real (otra teoría).

+1

En muchos casos, la preparación de los datos para una transacción lleva mucho tiempo. Si, como dices, la transacción se abre tan pronto como se inicia el bloque decorado, existe una motivación para separar bloques de preparación y bloques de transacción ... Si este es el caso, entonces debe documentarse en la documentación de django en la sección de transacciones . – Jonathan

Cuestiones relacionadas