Проблема отката / фиксации транзакций в Django models.py - PullRequest
0 голосов
/ 04 февраля 2011

Я прочитал документацию по транзакциям, но все еще немного потерял, как я должен это делать.Допустим, у меня есть класс Book (имя, содержимое, left_key, right_key, level) в models.py с методами, которые хранят содержимое книги в виде вложенных наборов.Основной метод, который я хочу использовать:

@transaction.commit_on_success
def add_node(self,right,level):
    cursor = connection.cursor()
    cursor.execute("UPDATE cms_Book  SET left_key = left_key + 2, right_key = right_key + 2 WHERE left_key > %s",[right])
    cursor.execute("UPDATE cms_Book SET right_key = right_key + 2 WHERE right_key >= %s AND left_key < %s ",[right,right])
    cursor.execute("INSERT INTO cms_Book SET left_key = %s, right_key = %s + 1, level = %s + 1, content='roar'",[right,right,level])

Но поскольку вставка в основном зависит от ключей, переданных из шаблона в качестве параметров, мне нужно проверить, вставлены ли правильные ключи. Даже если, например, вставлены неправильные ключи, узел все равно будетбудет добавлено, и ничего не сломается, и никакое исключение не произойдет, но логика сломается, что не очень хорошо, в случае, если мне нужно получить определенные узлы, а не все из них.

Так что у меня есть несколько других методов, чтобы проверитьправильна ли логика или нет.Вот один из них:

 def check_count(self):
    q = Book.objects.aggregate(min_key = Min('left_key'),max_key= Max('right_key'),count_all = Count('id'))
    return q

Что мне нужно, это отчасти выполнить все действия в методе add_node, а затем проверить, не нарушает ли логика методы проверки, если это не так, зафиксировать всев противном случае откат.Что я вроде не понимаю, так это то, что если я использую try, кроме block, мне нужно db, чтобы создать какую-то ошибку / исключение, чего не произойдет, или, например, сделать:

   if (check_my_table_for_all_different_keys == none):
           transactions.commit
   else:
           transactions.rollback

check_my_table_for_all_different_keys - ничего не возвращает, если все ключи уникальны, в противном случае возвращает id объектов, которые идентичны или имеют одинаковые ключи.Также я не уверен, как именно должна выглядеть деталь, где я фиксирую все 3 транзакции, в случае, если моя логика на если - еще структура верна, что я думаю, нет.

Ответы [ 3 ]

3 голосов
/ 01 апреля 2016

Джанго 1,9 +

Django предоставляет единый API для управления транзакциями базы данных.

атомарный (используя = Нет, точка сохранения = Истина) [источник] ¶ Атомность является определяющим свойством транзакций базы данных. atomic позволяет нам создать блок кода, в котором гарантируется атомарность базы данных. Если блок кода успешно завершен, изменения фиксируются в базе данных. Если есть исключение, изменения отменяются.

атомные блоки могут быть вложенными. В этом случае, когда внутренний блок завершается успешно, его эффекты все еще можно откатить, если во внешнем блоке возникает исключение в более поздней точке.

atomic может использоваться как декоратор:

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()
3 голосов
/ 04 февраля 2011

Документация django по управлению транзакциями показывает два возможных пути. В примерах предполагается, что у вас есть функция valid (например, ваша check_my_table_for_all_different_keys), которая проверяет текущее состояние базы данных и возвращает false, если данные неверны.

используйте commit_on_success (как вы сейчас делаете)

Таким образом, ожидающая транзакция фиксируется после успешного завершения функции. Когда возникает исключение, оно откатывается.

@transaction.commit_on_success
def add_node(self, right, level):
  # insert/update entries
  if not valid():
      raise Exception('invalid state')

Вызывающий код должен обработать это исключение, но знает, был ли узел успешно добавлен.

использование commit_manually

Это более явно, в том смысле, что вы должны фиксировать или откатывать при необходимости. Ваш пример уже идет в этом направлении.

@transaction.commit_manually
def add_node(self, right, level):
  # insert/update entries
  if valid():
      transaction.commit()
  else:
      transaction.rollback()

Никаких исключений не возникает, «ошибки» замалчиваются. Транзакция была совершена, если все было правильно, или была отменена в противном случае.

0 голосов
/ 04 февраля 2011

Теперь, когда все работает нормально. Я думаю, что я должен предоставить полный код, если кто-нибудь когда-нибудь будет таким же глупым, как я, и застрянет =). Итак, у нас есть класс Book (name, content, left_key, right_key, level) в models.py с методами:

check_difference возвращает false, если все ключи уникальны, в противном случае он возвращает true, поскольку все пары, содержащие одинаковые ключи, выбираются и помещаются в переменную q . Так что если что-то возвращается, len (q)> 0

def check_difference(self):
    cursor = connection.cursor()
    cursor.execute("SELECT t1.id, COUNT(t1.id) AS rep, MAX(t3.right_key) AS max_right \
                    FROM cms_Book AS t1, cms_Book AS t2, cms_Book AS t3\
                    WHERE t1.left_key <> t2.left_key \
                    AND t1.left_key <> t2.right_key \
                    AND t1.right_key <> t2.left_key \
                    AND t1.right_key <> t2.right_key \
                    GROUP BY t1.id \
                    HAVING max_right <> SQRT(4 * rep + 1) + 1 ")
    q = cursor.fetchall()
    if len(q) > 0:
        return True
    else:
        return False

Здесь я выполняю 3 запроса, проверяю таблицу на правильность, и если все в порядке, все ключи уникальны и check_difference возвращает false, тогда мы фиксируем все запросы и сохраняем в базе данных, в противном случае отката.

@transaction.commit_manually
def add_node(self,right,level):
    cursor = connection.cursor()
    cursor.execute("UPDATE cms_Book  SET left_key = left_key + 2, right_key = right_key + 2 WHERE left_key > %s",[right])

    cursor.execute("UPDATE cms_Book SET right_key = right_key + 2 WHERE right_key >= %s AND left_key < %s ",[right,right])

    cursor.execute("INSERT INTO cms_Book SET left_key = %s, right_key = %s + 1, level = %s + 1, content='roar'",[right,right,level])
    check = self.check_difference()
    if check == True:
        transaction.rollback()
    else:
        transaction.commit()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...