откат транзакции в методе сохранения - PullRequest
5 голосов
/ 04 июля 2010

У меня есть следующий фрагмент кода, переопределяющий метод сохранения модели:

@transaction.commit_on_success
def save(self, *args, **kwargs):

    try:
        transaction.commit()
        self.qa.vote_down_count += 1
        self.qa.save()

        super(self.__class__, self).save(*args, **kwargs)

    except:
        transaction.rollback()
        raise
    else:
        transaction.commit()

Ожидаемое поведение будет следующим: атрибут self.qa voice_down_count увеличивается на единицу, но если любое исключение возникает вметод super (self) save для отката транзакции (это означает, что self.qa.vote_down_count + = 1 не зафиксировано в базе данных).

Фактическое поведение: self.qa.vote_down_count + = 1 зафиксированов базу данных, даже если исключение IntegrityError возникает из супер (самостоятельного) сохранения.

Любые мысли?

Ответы [ 3 ]

6 голосов
/ 04 июля 2010

Почему бы просто не сделать:

@transaction.commit_manually
def save(self, *args, **kwargs):
    try:
        super(self.__class__, self).save(*args, **kwargs)
        self.qa.vote_down_count += 1
        self.qa.save()
    except:
        transaction.rollback()
        raise
    else:
        transaction.commit()

Вот как документы подразумевают это, хотя они говорят, что делают это в вашей функции просмотра, поэтому вам может не понадобиться@transaction.commit_manually для метода save(), вместо этого поместив его в представление.

3 голосов
/ 04 июля 2010

Попробуйте использовать точки сохранения . Примерно так:

def save(self, *args, **kwargs):

try:
    sid = transaction.savepoint()
    self.qa.vote_down_count += 1
    self.qa.save()

    super(self.__class__, self).save(*args, **kwargs)

except:
    transaction.rollback(sid)
    raise
else:
    transaction.commit(sid)
1 голос
/ 07 октября 2011

Я думаю, что ответ Майка ДеСимона - правильный.

Что касается базы данных, в зависимости от используемой вами версии MySQL (если вы ее используете), возможно, что таблицы вашей базы данных используют движок MyISAM, что делаетне поддерживает транзакции.

Чтобы проверить это, просто запустите в оболочке mysql:

SELECT TABLE_NAME, 
    ENGINE 
    FROM information_schema.TABLES 
    where TABLE_SCHEMA = 'your_db_name' ;

Вы можете изменить свои таблицы на InnoDB и установить default_storage_engine на innodb в конфигурации MySQL.(Подробности здесь: http://parasjain.net/2010/06/08/how-to-switch-to-innodb-database-in-mysql/.

После этого транзакции должны работать. Лучше использовать Postgres, но если вы хотите использовать MySQL / InnoDB, то, вероятно, вам понадобится обходной путь для загрузки приборов с прямыми ссылками(BugFix уже присутствует в Django Trunk, и я также перенес его в Django 1.3.1, см. Django 1.3.1.1 на Github ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...