Buscar..


Observaciones

Las transacciones son bloques protectores donde las sentencias de SQL solo son permanentes si todas pueden tener éxito como una sola acción atómica. El ejemplo clásico es una transferencia entre dos cuentas donde solo puede tener un depósito si el retiro fue exitoso y viceversa. Las transacciones imponen la integridad de la base de datos y protegen los datos contra los errores del programa o las fallas de la base de datos. Básicamente, debería usar bloques de transacciones cuando tenga una serie de sentencias que deben ejecutarse juntas o no deben ejecutarse.

Ejemplo basico

Por ejemplo:

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

Este ejemplo solo tomará dinero de David y se lo dará a Mary si ni el retiro ni el depósito generan una excepción. Las excepciones forzarán un ROLLBACK que devuelve la base de datos al estado antes de que comience la transacción. Tenga en cuenta, sin embargo, que a los objetos no se les devolverán los datos de instancia a su estado previo a la transacción.

Diferentes clases de ActiveRecord en una sola transacción

Aunque se llama al método de clase de transacción en alguna clase de ActiveRecord, no es necesario que todos los objetos dentro del bloque de transacción sean instancias de esa clase. Esto se debe a que las transacciones son por conexión de base de datos, no por modelo.

En este ejemplo, un registro de saldo se guarda de manera transaccional aunque la transacción se llame en la clase de Cuenta:

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

El método de transacción también está disponible como un método de instancia de modelo. Por ejemplo, también puedes hacer esto:

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

Conexiones de base de datos múltiples

Una transacción actúa en una sola conexión de base de datos. Si tiene varias bases de datos específicas de clase, la transacción no protegerá la interacción entre ellas. Una solución es comenzar una transacción en cada clase cuyos modelos modifique:

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

Esta es una solución deficiente, pero las transacciones totalmente distribuidas están fuera del alcance de ActiveRecord.

guardar y destruir se envuelven automáticamente en una transacción

Tanto #save como #destroy vienen envueltos en una transacción que garantiza que todo lo que haga en las validaciones o devoluciones de llamada sucederá bajo su cobertura protegida. Por lo tanto, puede usar las validaciones para verificar los valores de los que depende la transacción o puede generar excepciones en las devoluciones de llamada para revertir, incluidas las devoluciones de llamada after_* .

Como consecuencia, los cambios en la base de datos no se ven fuera de su conexión hasta que se completa la operación. Por ejemplo, si intenta actualizar el índice de un motor de búsqueda en after_save el indexador no verá el registro actualizado. La after_commit llamada after_commit es la única que se activa una vez que se confirma la actualización.

Devoluciones de llamada

Hay dos tipos de devoluciones de llamada asociadas con las transacciones de after_commit y after_rollback : after_commit y after_rollback .

after_commit devoluciones de llamada after_commit se llaman en cada registro guardado o destruido dentro de una transacción inmediatamente después de que se confirma la transacción. after_rollback devoluciones de llamada after_rollback realizan en cada registro guardado o destruido dentro de una transacción inmediatamente después de que la transacción o el punto de salvaguarda se revierte.

Estas devoluciones de llamada son útiles para interactuar con otros sistemas, ya que se le garantizará que la devolución de llamada solo se ejecute cuando la base de datos se encuentre en un estado permanente. Por ejemplo, after_commit es un buen lugar para poner un gancho para borrar un caché, ya que borrarlo de una transacción podría hacer que el caché se regenere antes de actualizar la base de datos.

Deshacer una transacción

ActiveRecord::Base.transaction utiliza la excepción ActiveRecord::Rollback para distinguir una reversión deliberada de otras situaciones excepcionales. Normalmente, al generar una excepción, el método .transaction revertirá la transacción de la base de datos y pasará la excepción. Pero si ActiveRecord::Rollback una excepción ActiveRecord::Rollback , la transacción de la base de datos se retrotraerá, sin pasar la excepción.

Por ejemplo, podría hacer esto en su controlador para deshacer una transacción:

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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow