or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aggregations-helpers.mdattributes-relationships.mddata-types.mddatabase-entities.mddebugging-utilities.mdexception-handling.mdframework-integrations.mdindex.mdquery-operations.mdsecurity-permissions.mdsession-management.md

session-management.mddocs/

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

```