0
# Session Management
1
2
Database session and transaction management functions that control the lifecycle of database operations and ensure data consistency. Pony ORM uses a session-based approach where all database operations must occur within a database session context.
3
4
## Capabilities
5
6
### Session Decorator and Context Manager
7
8
The primary interface for managing database sessions and transactions.
9
10
```python { .api }
11
@db_session
12
def your_function():
13
"""Decorator for automatic database session management.
14
15
Automatically starts a database session at function entry and commits
16
or rolls back at function exit. Can be used as decorator or context manager.
17
18
Usage as decorator:
19
@db_session
20
def create_user(name, email):
21
return User(name=name, email=email)
22
23
Usage as context manager:
24
with db_session:
25
user = User(name="Alice", email="alice@example.com")
26
"""
27
28
class db_session:
29
def __init__(self, retry=0, immediate=False, ddl=False,
30
serializable=False, strict=False, optimistic=True,
31
retry_exceptions=(TransactionError,), allowed_exceptions=(),
32
sql_debug=None, show_values=None):
33
"""Initialize database session with configuration options.
34
35
Args:
36
retry: Number of retry attempts for failed transactions (default: 0)
37
immediate: Use immediate transaction mode (default: False)
38
ddl: Allow DDL operations in session (default: False)
39
serializable: Use serializable isolation level (default: False)
40
strict: Enable strict mode for session (default: False)
41
optimistic: Use optimistic concurrency control (default: True)
42
retry_exceptions: Exception types that trigger retry (default: (TransactionError,))
43
allowed_exceptions: Exceptions that don't cause rollback (default: ())
44
sql_debug: Enable SQL debugging for this session (default: None)
45
show_values: Show parameter values in debug output (default: None)
46
"""
47
48
def __enter__(self):
49
"""Enter session context."""
50
51
def __exit__(self, exc_type, exc_val, exc_tb):
52
"""Exit session context with automatic commit/rollback."""
53
54
def commit(self):
55
"""Commit current transaction."""
56
57
def rollback(self):
58
"""Rollback current transaction."""
59
60
```
61
62
### Transaction Control Functions
63
64
Functions for explicit transaction management within database sessions.
65
66
```python { .api }
67
def flush():
68
"""Flush pending changes to database without committing transaction.
69
70
Forces all pending INSERT, UPDATE, DELETE operations to be sent
71
to the database, making them visible within the current transaction
72
but not committed until the transaction ends.
73
"""
74
75
def commit():
76
"""Commit current transaction.
77
78
Permanently saves all changes made during the current database session.
79
After commit, a new transaction is automatically started.
80
"""
81
82
def rollback():
83
"""Rollback current transaction.
84
85
Discards all changes made during the current database session.
86
After rollback, a new transaction is automatically started.
87
"""
88
```
89
90
### Entity Proxy Management
91
92
Functions for working with entity proxies and lazy loading.
93
94
```python { .api }
95
def make_proxy(entity_instance):
96
"""Create EntityProxy wrapper for entity instance.
97
98
Args:
99
entity_instance: Entity object to wrap
100
101
Returns:
102
EntityProxy: Proxy object that enables lazy loading
103
104
Usage:
105
user_proxy = make_proxy(user)
106
# Proxy can be passed around and used later in different sessions
107
"""
108
109
class EntityProxy:
110
def __init__(self, entity_class, pk):
111
"""Initialize entity proxy.
112
113
Args:
114
entity_class: Entity class
115
pk: Primary key value
116
"""
117
118
def get(self):
119
"""Get actual entity instance (requires active db_session)."""
120
121
def exists(self):
122
"""Check if proxied entity still exists in database."""
123
```
124
125
### Legacy Transaction Decorator
126
127
Deprecated transaction management decorator maintained for backwards compatibility.
128
129
```python { .api }
130
@with_transaction
131
def your_function():
132
"""Legacy transaction decorator (deprecated).
133
134
Use db_session instead. Provided for backwards compatibility only.
135
"""
136
```
137
138
## Usage Examples
139
140
### Basic Session Management
141
142
```python
143
from pony.orm import *
144
145
# Using as decorator
146
@db_session
147
def create_user(name, email):
148
"""Function automatically runs in database session."""
149
user = User(name=name, email=email)
150
return user # Changes automatically committed at function exit
151
152
# Using as context manager
153
def manual_session_example():
154
with db_session:
155
user = User(name="Alice", email="alice@example.com")
156
# Changes automatically committed when exiting context
157
158
# Session is now closed, user object is detached
159
160
# Multiple operations in single session
161
@db_session
162
def bulk_operations():
163
# All operations happen in same transaction
164
user1 = User(name="Alice", email="alice@example.com")
165
user2 = User(name="Bob", email="bob@example.com")
166
167
# Update existing user
168
existing = User.get(name="Charlie")
169
existing.email = "charlie.new@example.com"
170
171
# Delete old users
172
delete(u for u in User if u.last_login < date(2020, 1, 1))
173
174
# All changes committed together at function exit
175
```
176
177
### Explicit Transaction Control
178
179
```python
180
@db_session
181
def explicit_transaction_example():
182
try:
183
# Create some entities
184
user = User(name="Alice", email="alice@example.com")
185
order = Order(user=user, total=99.99, date=datetime.now())
186
187
# Force changes to database (but not committed yet)
188
flush()
189
190
# Can now see the changes in current transaction
191
print(f"User ID: {user.id}") # ID is available after flush
192
193
# Some business logic that might fail
194
if order.total > 1000:
195
raise ValueError("Order too large")
196
197
# Explicitly commit if everything is ok
198
commit()
199
print("Transaction committed successfully")
200
201
except Exception as e:
202
print(f"Error occurred: {e}")
203
rollback() # Explicit rollback
204
raise
205
```
206
207
### Session Configuration
208
209
```python
210
# Session with custom configuration
211
with db_session(retry=3, optimistic=False, sql_debug=True):
212
# Operations with retry on failure and pessimistic locking
213
user = User.get_for_update(name="Alice") # Row lock
214
user.balance += 100
215
216
# Session allowing DDL operations
217
with db_session(ddl=True):
218
db.execute("CREATE INDEX idx_user_email ON User(email)")
219
220
# Serializable isolation level for strict consistency
221
with db_session(serializable=True):
222
# Critical financial operations
223
account = Account.get(id=123)
224
if account.balance >= 100:
225
account.balance -= 100
226
Transaction(account=account, amount=-100, type="withdrawal")
227
```
228
229
### Working with Entity Proxies
230
231
```python
232
# Create proxy outside of session
233
user_proxy = None
234
235
@db_session
236
def create_proxy():
237
global user_proxy
238
user = User.get(name="Alice")
239
user_proxy = make_proxy(user)
240
# Proxy can be used outside of this session
241
242
# Use proxy in different session
243
@db_session
244
def use_proxy():
245
if user_proxy.exists():
246
actual_user = user_proxy.get()
247
print(f"User: {actual_user.name}")
248
else:
249
print("User no longer exists")
250
251
# Proxies are useful for caching and passing between functions
252
def process_users():
253
proxies = []
254
255
with db_session:
256
# Create proxies for all users
257
for user in User.select():
258
proxies.append(make_proxy(user))
259
260
# Later, in different sessions
261
for proxy in proxies:
262
with db_session:
263
if proxy.exists():
264
user = proxy.get()
265
# Process user...
266
```
267
268
### Error Handling and Retry Logic
269
270
```python
271
from pony.orm import TransactionError, OptimisticCheckError
272
273
@db_session(retry=3, retry_exceptions=(TransactionError,))
274
def retry_on_conflict():
275
"""Automatically retry on transaction conflicts."""
276
user = User.get(name="Alice")
277
user.login_count += 1
278
# If concurrent modification occurs, will retry up to 3 times
279
280
@db_session
281
def custom_error_handling():
282
try:
283
# Risky operations
284
user = User(name="Duplicate", email="existing@example.com")
285
commit()
286
287
except IntegrityError as e:
288
print(f"Constraint violation: {e}")
289
rollback()
290
291
except OptimisticCheckError as e:
292
print(f"Concurrent modification detected: {e}")
293
rollback()
294
295
except Exception as e:
296
print(f"Unexpected error: {e}")
297
rollback()
298
raise
299
300
# Advanced session configuration for specific use cases
301
@db_session(optimistic=False, immediate=True)
302
def pessimistic_operations():
303
"""Use pessimistic locking for critical operations."""
304
account = Account.get_for_update(id=123) # Immediate row lock
305
account.balance -= 100
306
# No optimistic checks, immediate locking
307
```
308
309
### Session Best Practices
310
311
```python
312
# Good: Keep sessions short and focused
313
@db_session
314
def process_single_order(order_id):
315
order = Order[order_id]
316
order.status = "processed"
317
order.processed_at = datetime.now()
318
# Auto-commit at function exit
319
320
# Good: Batch related operations
321
@db_session
322
def daily_user_cleanup():
323
# All related operations in single transaction
324
inactive_users = select(u for u in User if u.last_login < cutoff_date)
325
for user in inactive_users:
326
# Archive user data
327
Archive(user_data=user.to_dict())
328
user.delete()
329
330
# Avoid: Long-running sessions
331
def bad_long_session():
332
with db_session:
333
for i in range(10000): # Don't do this
334
user = User(name=f"User{i}")
335
# Creates very large transaction
336
337
# Better: Batch processing with session management
338
def good_batch_processing():
339
batch_size = 100
340
for i in range(0, 10000, batch_size):
341
with db_session:
342
for j in range(i, min(i + batch_size, 10000)):
343
user = User(name=f"User{j}")
344
# Smaller transactions, better performance
345
```