Транзакция в рамках транзакции - PullRequest
8 голосов
/ 25 февраля 2010

Я хочу знать, безопасно ли и рекомендуется ли открывать транзакции внутри другой?

У меня есть метод:

def foo():
    session.begin
    try:
          stuffs
    except Exception, e:
         session.rollback()
         raise e
    session.commit()

и метод, который вызывает первый внутри транзакции:

def bar():
    stuffs
    try:
         foo()   #<<<< there it is :)
         stuffs
    except Exception, e:
        session.rollback()
        raise e
    session.commit()

если я получу исключение для метода foo, все операции будут откат? а все остальное будет работать нормально? спасибо !!

Ответы [ 3 ]

18 голосов
/ 26 февраля 2010

Существует два способа вложения транзакций в SQLAlchemy. Один из них - виртуальные транзакции, где SQLAlchemy отслеживает, сколько начальных значений вы создали, и выдает коммит только тогда, когда совершает самая внешняя транзакция. Откат однако выдается сразу. Поскольку транзакция является виртуальной - то есть база данных ничего не знает о вложенности, вы не сможете ничего сделать с этим сеансом после отката, пока не откатите все внешние транзакции. Чтобы разрешить использование виртуальных транзакций, добавьте аргумент subtransactions=True к вызову begin(). Эта функция существует, чтобы позволить вам использовать управление транзакциями внутри функций, которые могут вызывать друг друга, не отслеживая, находитесь ли вы внутри транзакции или нет. Чтобы это имело смысл, сконфигурируйте сеанс с autocommit=True и всегда выдавайте session.begin(subtransactions=True) в транзакционной функции.

Другой способ вложения транзакций - использование реальных вложенных транзакций. Они реализованы с использованием точек сохранения. Если вы откатываете вложенную транзакцию, все изменения, сделанные в этой транзакции, откатываются, но внешняя транзакция остается пригодной для использования, и любые изменения, сделанные внешней транзакцией, все еще остаются. Для использования вложенной транзакции выведите session.begin(nested=True) или просто session.begin_nested(). Вложенные транзакции поддерживаются не для всех баз данных. Функция конфигурации библиотеки набора тестов SQLAlchemy sqlalchemy.test.requires.savepoints говорит о поддержке:

    emits_warning_on('mssql', 'Savepoint support in mssql is experimental and may lead to data loss.'),
    no_support('access', 'not supported by database'),
    no_support('sqlite', 'not supported by database'),
    no_support('sybase', 'FIXME: guessing, needs confirmation'),
    exclude('mysql', '<', (5, 0, 3), 'not supported by database')

В PostgreSQL вложенные транзакции SQLAlchemy работают просто отлично.

0 голосов
/ 26 февраля 2010

В PostgreSQL вложенные транзакции работают просто отлично.

Ну, вы не получите ошибку (только предупреждение), это правда. Но вы не можете зафиксировать внутреннюю транзакцию и откатить внешнюю транзакцию, внешняя транзакция также откатит внутреннюю транзакцию.

НАЧАТЬ;

INSERT INTO x (foo) VALUES ('John');

НАЧАТЬ; - ВНИМАНИЕ!

INSERT INTO y (bar) VALUES ('Джейн');

COMMIT; - совершить внутреннюю транзакцию

ROLLBACK; - откатит обе вставки, а не только первую, ту, что в таблице "x"

Насколько мне известно, Oracle является одним из немногих, кто имеет такую ​​возможность.

0 голосов
/ 25 февраля 2010

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

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