0
# Transaction Management
1
2
ACID transaction handling for consistent database operations. Transactions provide atomicity, consistency, isolation, and durability guarantees for all database modifications. LMDB supports concurrent readers with exclusive writers using MVCC (Multi-Version Concurrency Control).
3
4
## Capabilities
5
6
### Transaction Creation
7
8
Create read-only or read-write transactions with optional parent transaction support and buffer management.
9
10
```python { .api }
11
class Environment:
12
def begin(self, db=None, parent=None, write: bool = False,
13
buffers: bool = False) -> Transaction:
14
"""
15
Begin a new transaction.
16
17
Parameters:
18
- db: Default database handle for transaction operations
19
- parent: Parent transaction (for nested transactions)
20
- write: Enable write operations (default read-only)
21
- buffers: Return buffer objects instead of copying data
22
23
Returns:
24
Transaction instance
25
26
Note:
27
Write transactions are exclusive - only one write transaction per environment.
28
Read transactions are concurrent and don't block each other or writers.
29
"""
30
```
31
32
### Transaction Lifecycle
33
34
Commit or abort transactions with proper resource cleanup and error handling.
35
36
```python { .api }
37
class Transaction:
38
def commit(self) -> None:
39
"""
40
Commit all operations in transaction and close it.
41
Changes become visible to other transactions.
42
43
Raises:
44
Various errors if commit fails (disk full, corruption, etc.)
45
"""
46
47
def abort(self) -> None:
48
"""
49
Abandon all operations and close transaction.
50
All changes are discarded without affecting database.
51
Safe to call multiple times.
52
"""
53
54
def id(self) -> int:
55
"""
56
Get unique transaction identifier.
57
58
Returns:
59
Transaction ID (monotonically increasing)
60
"""
61
```
62
63
### Data Retrieval
64
65
Read operations for accessing stored data with flexible default handling and multi-database support.
66
67
```python { .api }
68
class Transaction:
69
def get(self, key: bytes, default=None, db=None) -> bytes:
70
"""
71
Retrieve value for given key.
72
73
Parameters:
74
- key: Key to lookup (bytes object)
75
- default: Value returned if key not found
76
- db: Database handle (uses transaction default if None)
77
78
Returns:
79
Value bytes or default if key not found
80
"""
81
```
82
83
### Data Modification
84
85
Write operations for storing, updating, and removing data with extensive control options.
86
87
```python { .api }
88
class Transaction:
89
def put(self, key: bytes, value: bytes, dupdata: bool = True,
90
overwrite: bool = True, append: bool = False, db=None) -> bool:
91
"""
92
Store key-value pair in database.
93
94
Parameters:
95
- key: Key bytes (must not be empty)
96
- value: Value bytes
97
- dupdata: Allow duplicate keys (ignored if database doesn't support duplicates)
98
- overwrite: Replace existing value (False raises KeyExistsError if key exists)
99
- append: Optimize for appending (key must be >= all existing keys)
100
- db: Database handle
101
102
Returns:
103
True if key was inserted, False if key existed and was updated
104
105
Raises:
106
KeyExistsError: If overwrite=False and key exists
107
MapFullError: If database is full
108
"""
109
110
def replace(self, key: bytes, value: bytes, db=None) -> bytes:
111
"""
112
Replace existing value and return old value.
113
114
Parameters:
115
- key: Key to replace
116
- value: New value
117
- db: Database handle
118
119
Returns:
120
Previous value
121
122
Raises:
123
NotFoundError: If key doesn't exist
124
"""
125
126
def pop(self, key: bytes, db=None) -> bytes:
127
"""
128
Get value and delete key in single operation.
129
130
Parameters:
131
- key: Key to retrieve and delete
132
- db: Database handle
133
134
Returns:
135
Value that was stored
136
137
Raises:
138
NotFoundError: If key doesn't exist
139
"""
140
141
def delete(self, key: bytes, value: bytes = b'', db=None) -> bool:
142
"""
143
Delete key-value pair from database.
144
145
Parameters:
146
- key: Key to delete
147
- value: Specific value to delete (for duplicate keys, empty for any value)
148
- db: Database handle
149
150
Returns:
151
True if key was found and deleted
152
153
Raises:
154
NotFoundError: If key doesn't exist (when value specified)
155
"""
156
```
157
158
### Database Operations
159
160
Transaction-scoped database management including statistics and database deletion.
161
162
```python { .api }
163
class Transaction:
164
def stat(self, db) -> dict:
165
"""
166
Get database statistics within transaction context.
167
168
Parameters:
169
- db: Database handle
170
171
Returns:
172
Dictionary with statistics:
173
- psize: Page size
174
- depth: B-tree depth
175
- branch_pages: Internal pages
176
- leaf_pages: Leaf pages
177
- overflow_pages: Overflow pages
178
- entries: Data items
179
"""
180
181
def drop(self, db, delete: bool = True) -> None:
182
"""
183
Empty or delete database.
184
185
Parameters:
186
- db: Database handle
187
- delete: If True, delete database; if False, empty database
188
189
Note:
190
Cannot delete the default database, only empty it
191
"""
192
```
193
194
### Cursor Creation
195
196
Create cursors for iteration and positioned access within transaction context.
197
198
```python { .api }
199
class Transaction:
200
def cursor(self, db=None) -> Cursor:
201
"""
202
Create cursor for iterating over database.
203
204
Parameters:
205
- db: Database handle (uses transaction default if None)
206
207
Returns:
208
Cursor instance bound to this transaction and database
209
"""
210
```
211
212
### Usage Examples
213
214
#### Basic Transaction Operations
215
216
```python
217
import lmdb
218
219
env = lmdb.open('/path/to/database')
220
221
# Write transaction with context manager (recommended)
222
with env.begin(write=True) as txn:
223
# Store data
224
txn.put(b'user:1', b'{"name": "Alice", "age": 30}')
225
txn.put(b'user:2', b'{"name": "Bob", "age": 25}')
226
227
# Update existing data
228
txn.put(b'user:1', b'{"name": "Alice Smith", "age": 31}')
229
230
# Conditional insert (fails if key exists)
231
try:
232
txn.put(b'user:3', b'{"name": "Charlie"}', overwrite=False)
233
except lmdb.KeyExistsError:
234
print("User 3 already exists")
235
236
# Get and delete in one operation
237
old_value = txn.pop(b'user:2')
238
print(f"Removed user: {old_value}")
239
240
# Transaction auto-commits when leaving context successfully
241
242
# Read transaction
243
with env.begin() as txn:
244
user1 = txn.get(b'user:1')
245
if user1:
246
print(f"User 1: {user1}")
247
248
# Safe get with default
249
user99 = txn.get(b'user:99', default=b'Not found')
250
print(f"User 99: {user99}")
251
252
env.close()
253
```
254
255
#### Manual Transaction Management
256
257
```python
258
import lmdb
259
260
env = lmdb.open('/path/to/database')
261
262
# Manual transaction management (not recommended - use context managers)
263
txn = env.begin(write=True)
264
try:
265
txn.put(b'key1', b'value1')
266
txn.put(b'key2', b'value2')
267
268
# Simulate error condition
269
if some_error_condition:
270
txn.abort() # Discard changes
271
print("Transaction aborted")
272
else:
273
txn.commit() # Save changes
274
print("Transaction committed")
275
276
except Exception as e:
277
txn.abort() # Always abort on exception
278
print(f"Transaction failed: {e}")
279
280
env.close()
281
```
282
283
#### Multi-Database Transactions
284
285
```python
286
import lmdb
287
288
env = lmdb.open('/path/to/database', max_dbs=3)
289
290
# Open multiple databases
291
users_db = env.open_db(b'users')
292
posts_db = env.open_db(b'posts')
293
comments_db = env.open_db(b'comments')
294
295
# Atomic operations across multiple databases
296
with env.begin(write=True) as txn:
297
# Create user
298
user_id = b'user:123'
299
txn.put(user_id, b'{"name": "Alice"}', db=users_db)
300
301
# Create post by user
302
post_id = b'post:456'
303
txn.put(post_id, b'{"user_id": "123", "title": "Hello World"}', db=posts_db)
304
305
# Add comment to post
306
comment_id = b'comment:789'
307
txn.put(comment_id, b'{"post_id": "456", "text": "Great post!"}', db=comments_db)
308
309
# All operations committed atomically
310
311
# Read from multiple databases
312
with env.begin() as txn:
313
user = txn.get(b'user:123', db=users_db)
314
post = txn.get(b'post:456', db=posts_db)
315
comment = txn.get(b'comment:789', db=comments_db)
316
317
print(f"User: {user}")
318
print(f"Post: {post}")
319
print(f"Comment: {comment}")
320
321
env.close()
322
```
323
324
#### Error Handling
325
326
```python
327
import lmdb
328
329
env = lmdb.open('/path/to/database')
330
331
try:
332
with env.begin(write=True) as txn:
333
txn.put(b'key1', b'value1')
334
335
# This might fail if database is full
336
large_value = b'x' * 1000000
337
txn.put(b'large_key', large_value)
338
339
except lmdb.MapFullError:
340
print("Database is full - increase map_size")
341
342
except lmdb.Error as e:
343
print(f"LMDB error: {e}")
344
345
finally:
346
env.close()
347
```