You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/posts/2019/2019-05-14-using-python-sqlalchemy-session-in-multithreading.md
+22-64Lines changed: 22 additions & 64 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,89 +4,47 @@ authors:
4
4
categories:
5
5
- python
6
6
- multithreading
7
+
- asyncio
7
8
- sqlalchemy
8
9
comments: true
9
10
date:
10
11
created: 2019-05-14
11
-
description: Using Python SQLAlchemy session in multithreading by using contextmanager
12
-
or scope_session.
12
+
updated: 2025-05-14
13
+
description: Using Python SQLAlchemy session in multithreading and asyncio by using context manager
14
+
or scoped_session.
13
15
---
14
16
15
-
# Using Python SQLAlchemy session in multithreading
17
+
# Using Python SQLAlchemy session in concurrent threads or tasks
16
18
17
-
SQLAlchemy DB session is [not thread safe](https://docs.sqlalchemy.org/en/13/orm/session_basics.html#is-the-session-thread-safe). In this post, I will show you 2 ways to use it in a multithreading context.
19
+
SQLAlchemy DB session is [not thread safe](https://docs.sqlalchemy.org/en/20/orm/session_basics.html#is-the-session-thread-safe-is-asyncsession-safe-to-share-in-concurrent-tasks) for both sync or async session. [AsyncSession](https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html#sqlalchemy.ext.asyncio.AsyncSession) is only a thin proxy on top of a [Session](https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session)
18
20
19
-
<!-- more -->
20
-
21
-
## Way 1 - Using contextmanager to create a session per thread
22
-
23
-
Below is an example given by the official doc to show how to use the [contextmanager](https://docs.sqlalchemy.org/en/13/orm/session_basics.html#when-do-i-construct-a-session-when-do-i-commit-it-and-when-do-i-close-it) to construct, commit and close a SQLAlchemy session.
24
-
25
-
```python
26
-
### another way (but again *not the only way*) to do it ###
27
-
28
-
from contextlib import contextmanager
21
+
> The concurrency model for SQLAlchemy's `Session` and `AsyncSession` is therefore Session per thread, AsyncSession per task.
22
+
> The best way to ensure this use is by using the [standard context manager pattern](https://docs.sqlalchemy.org/en/20/orm/session_basics.html#session-getting) locally within the top level Python function that is inside the thread or task, which will ensure the lifespan of the `Session` or `AsyncSession` is maintained within a local scope.
23
+
> For applications that benefit from having a "global" `Session` where it's not an option to pass the [Session](https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session) object to specific functions and methods which require it, the [scoped_session](https://docs.sqlalchemy.org/en/20/orm/contextual.html#sqlalchemy.orm.scoped_session) approach can provide for a "thread local" Session object; see the section [Contextual/Thread-local Sessions](https://docs.sqlalchemy.org/en/20/orm/contextual.html#unitofwork-contextual) for background. Within the asyncio context, the [async_scoped_session](https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html#sqlalchemy.ext.asyncio.async_scoped_session) object is the asyncio analogue for [scoped_session](https://docs.sqlalchemy.org/en/20/orm/contextual.html#sqlalchemy.orm.scoped_session), however is more challenging to configure as it requires a custom "context" function.
29
24
25
+
<!-- more -->
30
26
31
-
@contextmanager
32
-
defsession_scope():
33
-
"""Provide a transactional scope around a series of operations."""
34
-
session = Session()
35
-
try:
36
-
yield session
37
-
session.commit()
38
-
except:
39
-
session.rollback()
40
-
raise
41
-
finally:
42
-
session.close()
43
-
44
-
45
-
defrun_my_program():
46
-
with session_scope() as session:
47
-
ThingOne().go(session)
48
-
ThingTwo().go(session)
49
-
```
50
-
51
-
Suppose we have a function called `f1` which does something with the session. And we need to call `f1` in a multithreading context.
52
-
All we need to do is to add the `session_scope()` around the `f1`:
27
+
## Way 1 - Using context manager to create a session per thread or task
53
28
54
29
```python
55
-
from contextlib import contextmanager
56
30
from multiprocessing.dummy import Pool as ThreadPool
57
31
58
-
# db_utils is a python file that creats the Session by using the factory sessionmaker(),
59
-
# not shown here.
60
-
from db_utils import Session
61
-
62
-
63
-
@contextmanager
64
-
defsession_scope():
65
-
"""Provide a transactional scope around a series of operations."""
66
-
session = Session()
67
-
try:
68
-
yield session
69
-
session.commit()
70
-
except:
71
-
session.rollback()
72
-
raise
73
-
finally:
74
-
session.close()
75
-
32
+
from sqlalchemy import create_engine
33
+
from sqlalchemy.orm import sessionmaker
76
34
77
-
deff1(session, number):
78
-
# do something around the session and the number...
0 commit comments