Ecto.Repo.transaction
transaction
, go back to Ecto.Repo module for more information.
Specs
transaction( fun_or_multi :: (... -> any()) | Ecto.Multi.t(), opts :: Keyword.t() ) :: {:ok, any()} | {:error, any()} | {:error, Ecto.Multi.name(), any(), %{required(Ecto.Multi.name()) => any()}}
Runs the given function or Ecto.Multi
inside a transaction.
Use with function
transaction/2
can be called with both a function of arity
zero or one. The arity zero function will just be executed as is,
while the arity one function will receive the repo of the transaction
as its first argument, similar to Ecto.Multi.run/3
.
If an unhandled error occurs the transaction will be rolled back
and the error will bubble up from the transaction function.
If no error occurred the transaction will be committed when the
function returns. A transaction can be explicitly rolled back
by calling rollback/1
, this will immediately leave the function
and return the value given to rollback
as {:error, value}
.
A successful transaction returns the value returned by the function
wrapped in a tuple as {:ok, value}
.
If transaction/2
is called inside another transaction, the function
is simply executed, without wrapping the new transaction call in any
way. If there is an error in the inner transaction and the error is
rescued, or the inner transaction is rolled back, the whole outer
transaction is marked as tainted, guaranteeing nothing will be committed.
Use with Ecto.Multi
Besides functions, transactions can be used with an Ecto.Multi
struct.
A transaction will be started, all operations applied and in case of
success committed returning {:ok, changes}
. In case of any errors
the transaction will be rolled back and
{:error, failed_operation, failed_value, changes_so_far}
will be
returned.
You can read more about using transactions with Ecto.Multi
as well as
see some examples in the Ecto.Multi
documentation.
Options
See the "Shared options" section at the module documentation for more options.
Examples
import Ecto.Changeset, only: [change: 2]
MyRepo.transaction(fn ->
MyRepo.update!(change(alice, balance: alice.balance - 10))
MyRepo.update!(change(bob, balance: bob.balance + 10))
end)
# When passing a function of arity 1, it receives the repository itself
MyRepo.transaction(fn repo ->
repo.insert!(%Post{})
end)
# Roll back a transaction explicitly
MyRepo.transaction(fn ->
p = MyRepo.insert!(%Post{})
if not Editor.post_allowed?(p) do
MyRepo.rollback(:posting_not_allowed)
end
end)
# With Ecto.Multi
Ecto.Multi.new()
|> Ecto.Multi.insert(:post, %Post{})
|> MyRepo.transaction