1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109# Connections and Transactions
Databases handles database connection pooling and transaction management
with minimal fuss. It'll automatically deal with acquiring and releasing
connections to the pool as needed, and supports a simple transaction API
that transparently handles the use of either transactions or savepoints.
## Connecting and disconnecting
You can control the database connect/disconnect, by using it as a async context manager.
```python
async with Database(DATABASE_URL) as database:
...
```
Or by using explicit connection and disconnection:
```python
database = Database(DATABASE_URL)
await database.connect()
...
await database.disconnect()
```
If you're integrating against a web framework, then you'll probably want
to hook into framework startup or shutdown events. For example, with
[Starlette][starlette] you would use the following:
```python
@app.on_event("startup")
async def startup():
await database.connect()
@app.on_event("shutdown")
async def shutdown():
await database.disconnect()
```
## Connection options
The PostgreSQL and MySQL backends provide a few connection options for SSL
and for configuring the connection pool.
```python
# Use an SSL connection.
database = Database('postgresql+asyncpg://localhost/example?ssl=true')
# Use a connection pool of between 5-20 connections.
database = Database('mysql+aiomysql://localhost/example?min_size=5&max_size=20')
```
You can also use keyword arguments to pass in any connection options.
Available keyword arguments may differ between database backends.
```python
database = Database('postgresql+asyncpg://localhost/example', ssl=True, min_size=5, max_size=20)
```
## Transactions
Transactions are managed by async context blocks.
A transaction can be acquired from the database connection pool:
```python
async with database.transaction():
...
```
It can also be acquired from a specific database connection:
```python
async with database.connection() as connection:
async with connection.transaction():
...
```
For a lower-level transaction API:
```python
transaction = await database.transaction()
try:
...
except:
await transaction.rollback()
else:
await transaction.commit()
```
You can also use `.transaction()` as a function decorator on any async function:
```python
@database.transaction()
async def create_users(request):
...
```
Transaction blocks are managed as task-local state. Nested transactions
are fully supported, and are implemented using database savepoints.
Transaction isolation-level can be specified if the driver backend supports that:
```python
async with database.transaction(isolation="serializable"):
...
```
[starlette]: https://github.com/encode/starlette