Force a Rollback Within a Transaction

Learn how to explicitly rollback within a transaction.

How Repo.transaction works

Notice that we’ve been using insert! with a bang rather than insert. The two functions are identical except for one crucial difference—insert will return {: error, value} if the insert fails, but insert! will raise an error. This is a convention used in many Elixir libraries, and it’s essential when executing transactions with a function.

The documentation for Repo.transaction says

“If an unhandled error occurs, the transaction will be rolled back, and the error will bubble up from the transaction function.”

This means that only unhandled errors will trigger the rollback behavior—the return value of {:error, value} from one of the operations isn’t going to cut it.

Example of when forcing a rollback is needed

We can demonstrate this by rewriting our transaction by inserting changesets rather than schema structs. If we pass an invalid changeset to insert (without the bang), it will return an :error tuple without raising an error. We’ll add some debug output so we can see exactly what’s going on.

Get hands-on with 1200+ tech skills courses.