Поиск…


замечания

Транзакции являются защитными блоками, где заявления SQL являются только постоянными, если все они могут быть успешными как одно атомное действие. Классический пример - это передача между двумя учетными записями, где вы можете получить только депозит, если списание отменено, и наоборот. Транзакции обеспечивают целостность базы данных и защищают данные от ошибок программы или разбивки баз данных. Поэтому в основном вы должны использовать блоки транзакций, когда у вас есть несколько операторов, которые должны выполняться вместе или вообще не выполняться.

Основной пример

Например:

ActiveRecord::Base.transaction do
  david.withdrawal(100)
  mary.deposit(100)
end

Этот пример будет брать деньги только у Дэвида и отдать его Мэри, если ни отход, ни депозит не приведут к исключению. Исключения заставят ROLLBACK вернуть базу данных в состояние до начала транзакции. Однако имейте в виду, что у объектов не будет данных экземпляра, возвращаемых в их предварительное транзакционное состояние.

Различные классы ActiveRecord в одной транзакции

Хотя метод класса транзакции вызывается в некотором классе ActiveRecord, объекты внутри блока транзакций не обязательно должны быть экземплярами этого класса. Это связано с тем, что транзакции - это подключение по каждой базе данных, а не для каждой модели.

В этом примере запись баланса сохраняется в транзакции, даже если транзакция вызывается в классе Account:

Account.transaction do
  balance.save!
  account.save!
end

Метод транзакции также доступен как метод экземпляра модели. Например, вы также можете сделать это:

balance.transaction do
  balance.save!
  account.save!
end

Несколько соединений с базой данных

Транзакция действует на одно соединение с базой данных. Если у вас несколько баз данных, специфичных для класса, транзакция не будет защищать взаимодействие между ними. Одним из способов является начало транзакции для каждого класса, чьи модели вы изменяете:

Student.transaction do
  Course.transaction do
    course.enroll(student)
    student.units += course.units
  end
end

Это плохое решение, но полностью распределенные транзакции выходят за рамки ActiveRecord.

сохранение и уничтожение автоматически завертываются в транзакцию

Оба метода #save и #destroy завершаются транзакцией, которая гарантирует, что все, что вы делаете при проверке или обратном вызове, произойдет под защищенной оболочкой. Таким образом, вы можете использовать проверки для проверки значений, на которые зависит транзакция, или вы можете after_* исключения в обратных after_* для отката, включая after_* callbacks.

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

Callbacks

Существует два типа обратных вызовов, связанных с транзакциями и after_rollback транзакций: after_commit и after_rollback .

after_commit callbacks after_commit для каждой записи, сохраненной или уничтоженной в транзакции сразу после совершения транзакции. after_rollback вызовы after_rollback вызываются в каждой записи, сохраненной или уничтоженной в транзакции сразу после откат транзакции или точки сохранения.

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

Откат транзакции

ActiveRecord::Base.transaction использует исключение ActiveRecord::Rollback чтобы отличить преднамеренный откат от других исключительных ситуаций. Обычно повышение исключения приводит к .transaction метод .transaction откатывается от транзакции базы данных и передает исключение. Но если вы ActiveRecord::Rollback исключение ActiveRecord::Rollback , транзакция базы данных будет отброшена, не передавая исключение.

Например, вы можете сделать это в своем контроллере для отката транзакции:

class BooksController < ActionController::Base
  def create
    Book.transaction do
      book = Book.new(params[:book])
      book.save!
      if today_is_friday?
        # The system must fail on Friday so that our support department
        # won't be out of job. We silently rollback this transaction
        # without telling the user.
        raise ActiveRecord::Rollback, "Call tech support!"
      end
    end
    # ActiveRecord::Rollback is the only exception that won't be passed on
    # by ActiveRecord::Base.transaction, so this line will still be reached
    # even on Friday.
    redirect_to root_url
  end
end


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow