Szukaj…


Uwagi

Transakcje są blokami ochronnymi, w których instrukcje SQL są trwałe tylko wtedy, gdy wszystkie mogą odnieść sukces jako jedna akcja atomowa. Klasycznym przykładem jest przelew między dwoma kontami, na którym można wpłacić depozyt tylko wtedy, gdy wypłata się powiodła i na odwrót. Transakcje wymuszają integralność bazy danych i chronią dane przed błędami programu lub awariami bazy danych. Zasadniczo powinieneś używać bloków transakcji, ilekroć masz wiele instrukcji, które muszą być wykonane razem lub wcale.

Podstawowy przykład

Na przykład:

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

Ten przykład zabierze Dawidowi pieniądze i przekaże je Maryi, jeśli ani wypłata, ani depozyt nie spowodują wyjątku. Wyjątki wymuszą ROLLBACK, który przywraca bazę danych do stanu przed rozpoczęciem transakcji. Należy jednak pamiętać, że dane obiektów nie zostaną przywrócone do stanu sprzed transakcji.

Różne klasy ActiveRecord w jednej transakcji

Chociaż metoda klasy transakcji jest wywoływana w przypadku niektórych klas ActiveRecord, wszystkie obiekty w bloku transakcji nie muszą być instancjami tej klasy. Wynika to z faktu, że transakcje dotyczą połączenia dla bazy danych, a nie dla modelu.

W tym przykładzie rekord salda jest zapisywany transakcyjnie, mimo że transakcja jest wywoływana w klasie Account:

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

Metoda transakcji jest również dostępna jako metoda instancji modelu. Na przykład możesz to zrobić:

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

Wiele połączeń z bazą danych

Transakcja działa na pojedyncze połączenie z bazą danych. Jeśli masz wiele baz danych specyficznych dla klasy, transakcja nie ochroni interakcji między nimi. Jednym obejściem jest rozpoczęcie transakcji na każdej klasie, której modele zmienisz:

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

To kiepskie rozwiązanie, ale w pełni rozproszone transakcje wykraczają poza zakres ActiveRecord.

zapisz i zniszcz są automatycznie pakowane w transakcję

Zarówno #save, jak i #destroy są pakowane w transakcję, która gwarantuje, że wszystko, co zrobisz podczas sprawdzania poprawności lub wywołania zwrotnego, będzie miało miejsce pod ochroną. Możesz więc użyć sprawdzania poprawności do sprawdzenia wartości, od których zależy transakcja, lub możesz zgłosić wyjątki w wywołaniach zwrotnych do wycofania, w tym wywołania zwrotne after_* .

W rezultacie zmiany w bazie danych nie są widoczne poza Twoim połączeniem, dopóki operacja nie zostanie zakończona. Na przykład, jeśli spróbujesz zaktualizować indeks wyszukiwarki w after_save indeksator nie zobaczy zaktualizowanego rekordu. Callback after_commit jest jedynym wyzwalanym po zatwierdzeniu aktualizacji.

Callbacki

Istnieją dwa rodzaje wywołań zwrotnych związanych z after_commit i after_rollback transakcji: after_commit i after_rollback .

wywołania zwrotne after_commit są wywoływane dla każdego rekordu zapisanego lub zniszczonego w transakcji natychmiast po zatwierdzeniu transakcji. wywołania zwrotne after_rollback są wywoływane przy każdym rekordzie zapisanym lub zniszczonym w transakcji natychmiast po wycofaniu transakcji lub punktu zapisu.

Te wywołania zwrotne są przydatne do interakcji z innymi systemami, ponieważ gwarantujemy, że wywołanie zwrotne jest wykonywane tylko wtedy, gdy baza danych jest w stanie stałym. Na przykład after_commit jest dobrym miejscem do zaczepienia się o wyczyszczenie pamięci podręcznej, ponieważ wyczyszczenie jej w ramach transakcji może spowodować after_commit pamięci podręcznej przed zaktualizowaniem bazy danych.

Cofanie transakcji

ActiveRecord::Base.transaction korzysta z wyjątku ActiveRecord::Rollback aby odróżnić celowe wycofywanie od innych wyjątkowych sytuacji. Zwykle zgłoszenie wyjątku spowoduje wycofanie transakcji bazy danych przez metodę .transaction i przekazanie wyjątku. Ale jeśli ActiveRecord::Rollback wyjątek ActiveRecord::Rollback , transakcja bazy danych zostanie wycofana bez przekazywania wyjątku.

Na przykład możesz to zrobić w kontrolerze, aby wycofać transakcję:

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow