Skip to content

Commit 6b86fb6

Browse files
committed
docs: document transaction usage and caveats
1 parent 06c0ec5 commit 6b86fb6

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,51 @@ $statement->execute();
136136

137137
You may also skip the `Manager` entirely and use `Leeqvip\Database\Connection` directly with the same config array.
138138

139+
#### Transactions
140+
141+
```php
142+
$connection->beginTransaction();
143+
try {
144+
$connection->execute(
145+
'UPDATE `accounts` SET `balance` = `balance` - :amount WHERE `id` = :id',
146+
['amount' => 100, 'id' => 1]
147+
);
148+
$connection->execute(
149+
'UPDATE `accounts` SET `balance` = `balance` + :amount WHERE `id` = :id',
150+
['amount' => 100, 'id' => 2]
151+
);
152+
$connection->commit();
153+
} catch (\Throwable $e) {
154+
$connection->rollBack();
155+
throw $e;
156+
}
157+
```
158+
159+
Or use the `transaction()` helper, which commits automatically when the callback returns and rolls back and re-throws when it throws. The callback receives the connection:
160+
161+
```php
162+
use Leeqvip\Database\Connection;
163+
164+
$balance = $connection->transaction(function (Connection $db) {
165+
$db->execute(
166+
'UPDATE `accounts` SET `balance` = `balance` - :amount WHERE `id` = :id',
167+
['amount' => 100, 'id' => 1]
168+
);
169+
return $db->query('SELECT `balance` FROM `accounts` WHERE `id` = :id', ['id' => 1])[0]['balance'];
170+
});
171+
```
172+
173+
Transactions can be nested. The inner ones are simulated with savepoints, so an inner `rollBack()` only undoes its own work and leaves the outer transaction intact. This also applies to `transaction()` calls inside a `transaction()` callback.
174+
175+
Two things to be aware of:
176+
177+
- Don't call `commit()` or `rollBack()` manually inside a `transaction()` callback. If the callback rolls back and then returns, `transaction()` throws a `LogicException` when it tries to commit; and anything the callback already committed manually cannot be undone by an outer `rollBack()`.
178+
- Some statements end the transaction implicitly, e.g. DDL statements like `ALTER TABLE` commit on MySQL. When the connection notices the underlying transaction is gone it throws a `LogicException` and resets its internal state, so it stays usable without further cleanup.
179+
139180
### Exceptions
140181

141182
- A missing `type` or an unknown connector throws `InvalidArgumentException` when the connection object is created (i.e. in `getConnection()`).
183+
- Calling `commit()` or `rollBack()` without an active transaction throws `LogicException`.
142184
- Connection and query failures throw `PDOException`.
143185

144186
### Testing

0 commit comments

Comments
 (0)