Rails 3. Вложенные транзакции. Исключение в дочернем блоке - PullRequest
3 голосов
/ 11 ноября 2010

Почему не выполняется откат изменений ActiveRecord во вложенных транзакциях после исключения в дочернем блоке?

Вот примеры:

1.


>> Client.transaction do
?>   Client.create(:name => 'Pavel')
>>   Client.transaction do
?>     Client.create(:name => 'Elena')
>>     raise ActiveRecord::Rollback
>>   end
>> end
=> nil
>> Client.all.map(&:name)
=> ["Pavel", "Elena"] # instead of []

2.


>> Client.transaction do
?>   Client.create(:name => 'Pavel')
>>   Client.transaction(:requires_new => true) do
?>     Client.create(:name => 'Elena')
>>     raise ActiveRecord::Rollback
>>   end
>> end
=> nil
>> Client.all.map(&:name)
=> ["Pavel", "Elena"] # instead of ["Pavel"]

Спасибо.

Debian GNU / Linux 5.0.6;

Ruby 1.9.2;

Ruby on Rails 3.0.1;

SQLite 3.7.3.

Ответы [ 2 ]

3 голосов
/ 18 января 2011

У меня та же проблема, и я могу точно продублировать ваш результат. Если я поднимаю ActiveRecord :: Rollback во внешнем блоке, тогда вся транзакция откатывается, но в противном случае ничего не откатывается.

Очевидно, что текущая версия ActiveRecord не знает, как делать вложенные транзакции с SQLite3, даже если ActiveRecord должен реализовывать вложенные транзакции с использованием точек сохранения, а SQLite поддерживает точки сохранения с 3.6.8.

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

> List.connection.supports_savepoints?
=> false

Ubuntu 11.04 - Натти Нарвал;

ruby ​​1.8.7 (2010-04-19, уровень исправления 253) [i486-linux], MBARI 0x8770, Ruby Enterprise Edition 2010.02;

Ruby on Rails 3.0.3;

sqlite3 gem 1.3.3

SQLite 3.7.2;

0 голосов
/ 07 июня 2013

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

пример:

begin -- starts transaction 1
  begin -- start transaction 2

    insert into something (foo) values ('bar');

  commit -- ends transaction 1
rollback -- is ignored

Первая commit или rollback всегда закрывает исходящую транзакцию.* Есть способ, которым базы данных могут фактически делать вложение.это будет использовать ранее упомянутые точки сохранения .пример

begin -- starts transaction 1
  savepoint foo -- starts "transaction" 2

    insert into something (foo) values ('bar');

  release -- commit for transaction 2
rollback -- roll back the data of the savepoint and everything else within transaction 1

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

Для самих рельсов есть ловушкахотя: функции создают и аналогично оборачиваются внутри транзакции.Итак, ваш первый пример приводит к следующему sql

begin  -- transaction.do
  begin  -- Client.create
    insert into clients ( name ) values ('Pavel')  -- Client.create
  commit  -- Client.create, closes the out-most transaction
  begin -- transaction.do
    begin  -- Client.create
      insert into clients ( name ) values ('Elena')  -- Client.create
    commit  -- Client.create, closes the out-most transaction

Так что ваше Исключение просто приходит с опозданием.

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

PS: Вы можете быть смущены -- в sql.Это однострочные комментарии в mysql ..

...