# Transaction & Savepoints

Transaction are safeguard to ensure than a list of operation on a database are only permanent if they can all succeed as atomic action.

In Clear, the usage of transaction is simple:

```ruby
Clear::SQL.transaction do
    yacine.withdraw(100)
    mary.deposit(100)
end
```

In the example above, if one of the method fail, the whole transaction block will be reverted to initial state.

## Rollback

You can manually rollback a transaction if something went wrong:

```ruby
Clear::SQL.transaction do
    yacine.withdraw(100)
    Clear::SQL.rollback if mary.is_suspicious?
    mary.deposit(100)
end
```

In this case, the block will be returned, nothing will be committed in the database and no error will be thrown

## Nested transaction

Nested transaction are not working, but save points are used for that. Let's take an example:

```ruby
Clear::SQL.transaction do
    puts "I do something"
    Clear::SQL.transaction do
        puts "I do another thing"
        Clear::SQL.rollback
        puts "This should not print"
    end
    puts "This will never reach too."
end
```

In this case, the output will be:

```
# BEGIN
I do something
I do another thing
# ROLLBACK
```

Since **nested transaction are not permitted**, rollback will rollback the top-most transaction. Any nested transaction block will perform SQL-wise, only the block content will be executed.

## Savepoints

For nested transaction, you may want to use save points:

```ruby
Clear::SQL.with_savepoint do
    puts "I do something"
    Clear::SQL.with_savepoint do
        puts "I do another thing"
        Clear::SQL.rollback
        puts "This should not print"
    end
    puts "Eventually, I do something else"
end
```

In this case, the output will be:

```
# BEGIN
# SAVEPOINT xxx1
I do something
# SAVEPOINT xxx2
I do another thing
# ROLLBACK TO SAVEPOINT xxx2
Eventually, I do something else
# RELEASE SAVEPOINT xxx1
# COMMIT
```

As you can see, save points are backed by a transaction block; rollback inside a save point block will rollback the block only and not all the transaction. Any unhandled exception will still rollback the full transaction.
