Recherche…


Remarques

Les transactions sont des blocs protecteurs où les instructions SQL ne sont permanentes que si elles peuvent toutes réussir en une seule action atomique. L'exemple classique est un transfert entre deux comptes où vous ne pouvez avoir de dépôt que si le retrait a réussi et vice versa. Les transactions renforcent l'intégrité de la base de données et protègent les données contre les erreurs de programme ou les pannes de base de données. Donc, fondamentalement, vous devez utiliser des blocs de transaction chaque fois que vous avez un certain nombre d'instructions qui doivent être exécutées ensemble ou pas du tout.

Exemple de base

Par exemple:

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

Cet exemple ne prendra que de l'argent de David et le donnera à Mary si ni le retrait ni le dépôt ne font exception. Les exceptions forceront un ROLLBACK qui renvoie la base de données à l'état avant le début de la transaction. Sachez cependant que les objets ne verront pas leurs données d’instance retournées à leur état pré-transactionnel.

Différentes classes ActiveRecord en une seule transaction

Bien que la méthode de la classe transaction soit appelée sur certaines classes ActiveRecord, les objets du bloc de transaction ne doivent pas nécessairement tous être des instances de cette classe. Cela est dû au fait que les transactions sont par connexion à la base de données, et non par modèle.

Dans cet exemple, un enregistrement de solde est enregistré en transaction même si la transaction est appelée dans la classe Account:

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

La méthode de transaction est également disponible en tant que méthode d'instance de modèle. Par exemple, vous pouvez également faire ceci:

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

Connexions de bases de données multiples

Une transaction agit sur une seule connexion à la base de données. Si vous avez plusieurs bases de données spécifiques à une classe, la transaction ne protégera pas l'interaction entre elles. Une solution consiste à commencer une transaction sur chaque classe dont vous modifiez les modèles:

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

C'est une solution médiocre, mais les transactions entièrement distribuées dépassent le cadre d'ActiveRecord.

sauvegarder et détruire sont automatiquement encapsulés dans une transaction

#Save et #destroy sont tous deux inclus dans une transaction qui garantit que tout ce que vous faites lors des validations ou des rappels se produira sous sa couverture protégée. Vous pouvez donc utiliser les validations pour vérifier les valeurs dont dépend la transaction ou vous pouvez élever les exceptions dans les rappels à la restauration, y after_* rappels after_* .

En conséquence, les modifications apportées à la base de données ne sont pas visibles en dehors de votre connexion tant que l'opération n'est pas terminée. Par exemple, si vous essayez de mettre à jour l'index d'un moteur de recherche dans after_save l'indexeur ne verra pas l'enregistrement mis à jour. Le rappel after_commit est le seul à être déclenché une fois la mise à jour after_commit .

Rappels

Il existe deux types de rappels associés aux transactions de after_commit et d' after_rollback : after_commit et after_rollback .

after_commit rappels after_commit sont appelés sur chaque enregistrement enregistré ou détruit dans une transaction immédiatement après la after_commit la transaction. after_rollback rappels after_rollback sont appelés sur chaque enregistrement enregistré ou détruit dans une transaction immédiatement après l'annulation de la transaction ou du point de sauvegarde.

Ces rappels sont utiles pour interagir avec d'autres systèmes, car vous serez assuré que le rappel n'est exécuté que lorsque la base de données est dans un état permanent. Par exemple, after_commit est un bon endroit pour effacer un cache, car sa suppression dans une transaction peut déclencher la régénération du cache avant la mise à jour de la base de données.

Faire reculer une transaction

ActiveRecord::Base.transaction utilise l'exception ActiveRecord::Rollback pour distinguer une annulation délibérée d'autres situations exceptionnelles. En règle générale, déclencher une exception entraîne la méthode .transaction pour .transaction la transaction de base de données et transmettre l'exception. Mais si vous ActiveRecord::Rollback une exception ActiveRecord::Rollback , la transaction de base de données sera annulée, sans transmettre l'exception.

Par exemple, vous pouvez le faire dans votre contrôleur pour annuler une transaction:

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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow