42 lines
1.5 KiB
Markdown
42 lines
1.5 KiB
Markdown
# Transactions
|
|
|
|
Every repository method (`get_items`, `create_item`, etc.) wraps its operation in a transaction via `self.transaction()`. `self.transaction()` reuses an existing session from the context if one exists, otherwise creates a new one.
|
|
|
|
## Explicit transaction
|
|
|
|
You can open an explicit transaction when you need to group several operations:
|
|
|
|
```python
|
|
async with repository.transaction():
|
|
product1 = await repository.create_item(ProductTable(name="Laptop", price=999.99))
|
|
product2 = await repository.create_item(ProductTable(name="Mouse", price=29.99))
|
|
```
|
|
|
|
If any operation raises an exception, the entire transaction is rolled back.
|
|
|
|
## Reusing an existing session
|
|
|
|
Nested `transaction()` calls yield the same session — no new savepoint is created:
|
|
|
|
```python
|
|
async with repository.transaction(), repository.transaction():
|
|
items = [item async for item in repository.get_items()]
|
|
```
|
|
|
|
## Nested transactions (savepoints)
|
|
|
|
`nested_transaction()` creates a SQLAlchemy savepoint. When no outer session exists it starts a new session with a savepoint. On exception the savepoint is rolled back, leaving any outer transaction unaffected:
|
|
|
|
```python
|
|
try:
|
|
async with repository.nested_transaction():
|
|
await repository.create_item(ProductTable(name="Keyboard", price=79.99))
|
|
raise ValueError("Rollback nested")
|
|
except ValueError:
|
|
pass
|
|
|
|
# Keyboard was rolled back; previous items remain
|
|
```
|
|
|
|
This is useful for partial rollback inside a larger transaction. See [Multi-Repo Transactions](container.md) for container-level savepoints.
|