Rollen

2017-08-11 3 views
1
eine Reihe von db-Transaktionen auf Ausnahme in Django zurück

mit Um zu beginnen, this GitHub project enthalten den Code, den ich zu diskutieren und über in diesem Beitrag zu fragen. Es ist ein nicht-proprietäres und kurzes Beispiel für etwas, an dem gerade von meinem Team gearbeitet wird.Rollen

Ich bin an einem Projekt arbeiten, wo wir Django Datenbank-Transaktionen verwenden, um Updates auf einer Tabelle für die Konvertierung in XML in der Vorbereitung zu tun, die für geschäftliche Zwecke verwendet werden kann. Wir haben früher gebrochen Code festgelegt transaction.atomic() Kontext-Manager unter Verwendung, um sicherzustellen, dass Fehler korrekt behandelt werden. Jede -Anweisung befindet sich in einem Kontextmanager, der wiederum in einer Funktion sitzt. Es gibt drei dieser Funktionen (set_yes(), set_no() und broken_query()) innerhalb einer anderen Funktion aufgerufen (bulk_set()) im Programm:

models.py

from __future__ import unicode_literals 
from django.db import connection, DatabaseError, transaction 
import pandas as pd 

from django.db import models 


class TestTable(models.Model): 
    value1 = models.IntegerField() 
    value2 = models.IntegerField() 
    same = models.CharField(max_length=3, null=True) 


def setup_table(): 
    """ 
    sets up the basic table. 
    several rows will have matching values, some won't. 
    :return: None 
    """ 
    row1 = TestTable(value1=1, value2=1) 
    row1.save() 

    row2 = TestTable(value1=2, value2=1) 
    row2.save() 

    row3 = TestTable(value1=56, value2=1) 
    row3.save() 

    row4 = TestTable(value1=10, value2=10) 
    row4.save() 


def set_yes(): 
    """ 
    sets "same" column on rows with matching value1 and value2 columns to "yes" 
    :return: None 
    """ 
    query = ''' 
     UPDATE db_app_testtable 
     SET same = 'yes' 
     WHERE value1 = value2 
    ''' 
    try: 
     with transaction.atomic(): 
      cursor = connection.cursor() 
      cursor.execute(query) 
    except DatabaseError as ex: 
     print "set_yes has error %s" % (ex) 
     raise 
    finally: 
     cursor.close() 
     print_table() 


def set_no(): 
    """ 
    sets "same" column on rows with differing value1 and value2 columns to "no" 
    :return: None 
    """ 
    query = ''' 
     UPDATE db_app_testtable 
     SET same = 'no' 
     WHERE value1 != value2 
    ''' 
    try: 
     with transaction.atomic(): 
      cursor = connection.cursor() 
      cursor.execute(query) 
    except DatabaseError as ex: 
     print "set_no has error %s" % (ex) 
     raise 
    finally: 
     cursor.close() 
     print_table() 


def broken_query(): 
    """ 
    a function meant to break. there is no column named 'different', so this should cause 
    a DatabaseError to be thrown upon execution. 
    :return: None 
    """ 
    query = ''' 
     UPDATE db_app_testtable 
     SET different = 'lol no' 
     WHERE value1 = value2 
    ''' 
    try: 
     with transaction.atomic(): 
      cursor = connection.cursor() 
      cursor.execute(query) 
    except DatabaseError as ex: 
     print "broken_query has error %s" % (ex) 
     raise 
    finally: 
     cursor.close() 
... 

def bulk_set(): 
    try: 
     set_no() 
     set_yes() 
     broken_query() 
    except Exception as gen_ex: 
     print "Exception has occurred." 
     raise 

Wie Sie sehen können, broken_query() wird nicht funktionieren, und dies ist von Entwurf. Wir versuchen, einen Codeblock zu entwerfen, die die Operationen von set_yes() und set_no() getan werden, wenn ein Rollback broken_query() versagt, die es unvermeidlich wird.

die Eigenschaften django.db.transaction.atomic() gegeben, ist das möglich? Lesen der documentation, es heißt: "Wenn der Block des Codes erfolgreich abgeschlossen ist, werden die Änderungen an die Datenbank übergeben. Wenn es eine Ausnahme gibt, werden die Änderungen zurückgesetzt." Meine Frage ist, kann dies erweitert werden, um zu machen andere Operationen, die im selben Codeblock aufgerufen werden, werden ebenfalls zurückgesetzt?

Antwort

0

Ja, im selben Block der with atomic.transaction, wenn Sie raise Exception aufrufen, haben Sie die Transaktionen zurückgesetzt.

+0

verstanden, aber das Unteilbarkeit erstreckt sich nur auf diese Transaktion. Ich möchte, dass sich die Transaktionen irgendwie wie ein Set verhalten, so dass bei einem Fehlschlag alle fehlschlagen und alle zurückgerollt werden. – nerdenator

+0

Sie müssen also alle Transaktionen im atomaren Block einschließen. – wololoooo

+0

Obwohl ich denke, dass es nicht empfohlen wird, funktioniert es. – wololoooo