Ricerca…


Osservazioni

Le transazioni sono blocchi protettivi in ​​cui le istruzioni SQL sono permanenti solo se riescono tutte come una sola azione atomica. L'esempio classico è un trasferimento tra due account in cui è possibile avere un deposito solo se il ritiro è riuscito e viceversa. Le transazioni rafforzano l'integrità del database e proteggono i dati dagli errori del programma o dalle interruzioni del database. Quindi in pratica dovresti usare i blocchi di transazione ogni volta che hai un numero di istruzioni che devono essere eseguite insieme o non del tutto.

Esempio di base

Per esempio:

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

Questo esempio prenderà solo denaro da David e lo consegnerà a Mary se né il prelievo né il deposito sollevano un'eccezione. Le eccezioni costringono un ROLLBACK che restituisce il database allo stato prima dell'inizio della transazione. Si noti, tuttavia, che gli oggetti non avranno i loro dati di istanza restituiti allo stato pre-transazione.

Classi ActiveRecord differenti in una singola transazione

Sebbene il metodo della classe di transazione sia chiamato su alcune classi ActiveRecord, gli oggetti all'interno del blocco di transazione non devono necessariamente essere tutte istanze di quella classe. Questo perché le transazioni sono per connessione al database, non per modello.

In questo esempio, un record di saldo viene salvato a livello di transazione anche se la transazione viene richiamata nella classe Account:

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

Il metodo di transazione è anche disponibile come metodo di istanza del modello. Ad esempio, puoi anche fare questo:

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

Più connessioni al database

Una transazione agisce su una singola connessione al database. Se si dispone di più database specifici della classe, la transazione non proteggerà l'interazione tra di loro. Una soluzione alternativa è iniziare una transazione su ogni classe di cui modifichiamo i modelli:

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

Questa è una soluzione scadente, ma le transazioni completamente distribuite vanno oltre lo scopo di ActiveRecord.

salva e distruggi automaticamente in una transazione

Sia #save che #destroy vengono racchiusi in una transazione che garantisce che qualunque cosa tu faccia in convalide o callback avverrà sotto la sua copertina protetta. Pertanto, è possibile utilizzare le convalide per verificare i valori da cui dipende la transazione oppure è possibile generare eccezioni nei callback per il rollback, inclusi after_* callbacks.

Di conseguenza, le modifiche al database non vengono visualizzate al di fuori della connessione fino al completamento dell'operazione. Ad esempio, se si tenta di aggiornare l'indice di un motore di ricerca in after_save l'indicizzatore non vedrà il record aggiornato. Il callback after_commit è l'unico che viene attivato una volta eseguito il commit dell'aggiornamento.

callback

Esistono due tipi di callback associati alle transazioni di after_commit e after_rollback : after_commit e after_rollback .

after_commit callback after_commit vengono richiamati su ogni record salvato o distrutto all'interno di una transazione immediatamente dopo il commit della transazione. after_rollback callback after_rollback vengono richiamati su ogni record salvato o after_rollback all'interno di una transazione immediatamente dopo il rollback della transazione o del punto di salvataggio.

Questi callback sono utili per l'interazione con altri sistemi poiché è garantito che la richiamata viene eseguita solo quando il database si trova in uno stato permanente. Ad esempio, after_commit è un buon punto per mettere un aggancio per svuotare una cache poiché la sua eliminazione da una transazione potrebbe innescare la rigenerazione della cache prima che il database venga aggiornato.

Rollback di una transazione

ActiveRecord::Base.transaction utilizza l'eccezione ActiveRecord::Rollback per distinguere un rollback deliberato da altre situazioni eccezionali. Solitamente, sollevando un'eccezione, il metodo .transaction ripristina la transazione del database e trasmette l'eccezione. Ma se si solleva un'eccezione ActiveRecord::Rollback , la transazione del database verrà sottoposta a rollback, senza passare l'eccezione.

Ad esempio, è possibile farlo nel controller per eseguire il rollback di una transazione:

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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow