0
# Sessions and Transactions
1
2
Client sessions for transactions, causally consistent reads, and server session management providing ACID guarantees for multi-document operations.
3
4
## Capabilities
5
6
### ClientSession Interface
7
8
Primary interface for managing client sessions that enable transactions and causally consistent operations.
9
10
```java { .api }
11
/**
12
* Client session interface for transactions and causally consistent operations
13
*/
14
public interface ClientSession extends AutoCloseable {
15
/**
16
* Gets the server address this session is pinned to (if any)
17
* @return server address or null if not pinned
18
*/
19
ServerAddress getPinnedServerAddress();
20
21
/**
22
* Checks if this session has an active transaction
23
* @return true if transaction is active
24
*/
25
boolean hasActiveTransaction();
26
27
/**
28
* Gets the current transaction options
29
* @return transaction options or null if no active transaction
30
*/
31
TransactionOptions getTransactionOptions();
32
33
/**
34
* Starts a new transaction with default options
35
*/
36
void startTransaction();
37
38
/**
39
* Starts a new transaction with specific options
40
* @param transactionOptions configuration for the transaction
41
*/
42
void startTransaction(TransactionOptions transactionOptions);
43
44
/**
45
* Commits the current transaction
46
*/
47
void commitTransaction();
48
49
/**
50
* Aborts the current transaction
51
*/
52
void abortTransaction();
53
54
/**
55
* Executes a transaction body with automatic retry logic
56
* @param transactionBody the operation to execute in the transaction
57
* @return result from the transaction body
58
*/
59
<T> T withTransaction(TransactionBody<T> transactionBody);
60
61
/**
62
* Executes a transaction body with specific callback options
63
* @param transactionBody the operation to execute in the transaction
64
* @param options configuration for transaction callback behavior
65
* @return result from the transaction body
66
*/
67
<T> T withTransaction(TransactionBody<T> transactionBody, TransactionOptions options);
68
69
/**
70
* Notifies the session that a message has been sent (internal use)
71
* @return true if the session should be considered active
72
*/
73
boolean notifyMessageSent();
74
75
/**
76
* Notifies the session that an operation has been initiated (internal use)
77
* @param operation the operation being initiated
78
* @return true if the operation should proceed
79
*/
80
boolean notifyOperationInitiated(Object operation);
81
82
/**
83
* Closes the session and releases server resources
84
*/
85
void close();
86
}
87
```
88
89
**Usage Examples:**
90
91
```java
92
import com.mongodb.client.ClientSession;
93
import com.mongodb.client.MongoClient;
94
import com.mongodb.client.MongoClients;
95
import com.mongodb.TransactionOptions;
96
import com.mongodb.ReadConcern;
97
import com.mongodb.WriteConcern;
98
99
// Basic session usage
100
try (MongoClient client = MongoClients.create()) {
101
try (ClientSession session = client.startSession()) {
102
MongoDatabase database = client.getDatabase("mydb");
103
MongoCollection<Document> collection = database.getCollection("accounts");
104
105
// Perform operations with session for causally consistent reads
106
Document account = collection.find(session, Filters.eq("accountId", "12345")).first();
107
collection.updateOne(session,
108
Filters.eq("accountId", "12345"),
109
Updates.inc("balance", 100));
110
}
111
}
112
113
// Manual transaction control
114
try (ClientSession session = client.startSession()) {
115
try {
116
session.startTransaction();
117
118
// Transfer money between accounts
119
collection.updateOne(session,
120
Filters.eq("accountId", "account1"),
121
Updates.inc("balance", -100));
122
123
collection.updateOne(session,
124
Filters.eq("accountId", "account2"),
125
Updates.inc("balance", 100));
126
127
session.commitTransaction();
128
System.out.println("Transfer completed successfully");
129
130
} catch (Exception e) {
131
session.abortTransaction();
132
System.err.println("Transfer failed, transaction aborted: " + e.getMessage());
133
throw e;
134
}
135
}
136
```
137
138
### TransactionBody Interface
139
140
Functional interface for defining transaction logic with automatic retry capabilities.
141
142
```java { .api }
143
/**
144
* Functional interface for transaction body execution
145
* Transaction bodies must be idempotent as they may be retried
146
*/
147
@FunctionalInterface
148
public interface TransactionBody<T> {
149
/**
150
* Executes the transaction logic
151
* This method must be idempotent as it may be retried on transient failures
152
* @return result of the transaction
153
* @throws Exception if the transaction should be aborted
154
*/
155
T execute() throws Exception;
156
}
157
```
158
159
**Usage Examples:**
160
161
```java
162
// Automatic transaction with retry logic
163
try (ClientSession session = client.startSession()) {
164
String result = session.withTransaction(() -> {
165
// This lambda must be idempotent
166
MongoDatabase database = client.getDatabase("ecommerce");
167
MongoCollection<Document> orders = database.getCollection("orders");
168
MongoCollection<Document> inventory = database.getCollection("inventory");
169
170
// Create order
171
Document order = new Document("orderId", UUID.randomUUID().toString())
172
.append("customerId", "customer123")
173
.append("items", Arrays.asList(
174
new Document("productId", "product456").append("quantity", 2)
175
))
176
.append("status", "pending")
177
.append("createdAt", new Date());
178
179
orders.insertOne(session, order);
180
181
// Update inventory
182
UpdateResult inventoryUpdate = inventory.updateOne(session,
183
Filters.eq("productId", "product456"),
184
Updates.inc("stock", -2));
185
186
if (inventoryUpdate.getMatchedCount() == 0) {
187
throw new IllegalStateException("Product not found in inventory");
188
}
189
190
// Return order ID
191
return order.getString("orderId");
192
});
193
194
System.out.println("Order created with ID: " + result);
195
}
196
197
// Transaction with specific options
198
TransactionOptions txnOptions = TransactionOptions.builder()
199
.readConcern(ReadConcern.SNAPSHOT)
200
.writeConcern(WriteConcern.MAJORITY)
201
.maxCommitTime(30L, TimeUnit.SECONDS)
202
.build();
203
204
try (ClientSession session = client.startSession()) {
205
Boolean transferResult = session.withTransaction(() -> {
206
// Complex business logic
207
return performAccountTransfer(session, "from123", "to456", 250.00);
208
}, txnOptions);
209
210
if (transferResult) {
211
System.out.println("Transfer completed successfully");
212
}
213
}
214
```
215
216
### Transaction Configuration
217
218
Configuration options for controlling transaction behavior and guarantees.
219
220
```java { .api }
221
/**
222
* Transaction configuration options
223
*/
224
public class TransactionOptions {
225
/**
226
* Read concern for transaction operations
227
*/
228
private ReadConcern readConcern;
229
230
/**
231
* Write concern for transaction commit
232
*/
233
private WriteConcern writeConcern;
234
235
/**
236
* Read preference for transaction operations
237
*/
238
private ReadPreference readPreference;
239
240
/**
241
* Maximum time for commit operation
242
*/
243
private Long maxCommitTimeMS;
244
245
// Builder pattern for configuration
246
public static Builder builder() { return new Builder(); }
247
248
public static class Builder {
249
public Builder readConcern(ReadConcern readConcern);
250
public Builder writeConcern(WriteConcern writeConcern);
251
public Builder readPreference(ReadPreference readPreference);
252
public Builder maxCommitTime(long maxCommitTime, TimeUnit timeUnit);
253
public TransactionOptions build();
254
}
255
}
256
```
257
258
**Usage Examples:**
259
260
```java
261
// Configure transaction for strong consistency
262
TransactionOptions strongConsistency = TransactionOptions.builder()
263
.readConcern(ReadConcern.SNAPSHOT)
264
.writeConcern(WriteConcern.MAJORITY)
265
.readPreference(ReadPreference.primary())
266
.maxCommitTime(60, TimeUnit.SECONDS)
267
.build();
268
269
// Configure transaction for performance
270
TransactionOptions performance = TransactionOptions.builder()
271
.readConcern(ReadConcern.LOCAL)
272
.writeConcern(WriteConcern.W1)
273
.readPreference(ReadPreference.primaryPreferred())
274
.maxCommitTime(10, TimeUnit.SECONDS)
275
.build();
276
277
// Use configuration in session
278
try (ClientSession session = client.startSession()) {
279
session.startTransaction(strongConsistency);
280
281
// Perform critical operations requiring strong consistency
282
performCriticalUpdate(session);
283
284
session.commitTransaction();
285
}
286
```
287
288
### Session Lifecycle Management
289
290
Best practices for managing session lifecycle and resource cleanup.
291
292
```java { .api }
293
// Session options configuration
294
ClientSessionOptions sessionOptions = ClientSessionOptions.builder()
295
.causallyConsistent(true)
296
.defaultTransactionOptions(TransactionOptions.builder()
297
.readConcern(ReadConcern.MAJORITY)
298
.writeConcern(WriteConcern.MAJORITY)
299
.build())
300
.build();
301
302
try (ClientSession session = client.startSession(sessionOptions)) {
303
// Session operations
304
}
305
```
306
307
**Advanced Session Usage:**
308
309
```java
310
// Long-running session with multiple transactions
311
try (ClientSession session = client.startSession()) {
312
// First transaction
313
session.withTransaction(() -> {
314
// Batch of related operations
315
processBatchOfOrders(session, orderBatch1);
316
return null;
317
});
318
319
// Some non-transactional work
320
generateReports(session);
321
322
// Second transaction
323
session.withTransaction(() -> {
324
// Another batch of operations
325
processBatchOfOrders(session, orderBatch2);
326
return null;
327
});
328
}
329
330
// Session with custom retry logic
331
private <T> T executeWithCustomRetry(ClientSession session, TransactionBody<T> body) {
332
int maxRetries = 3;
333
int attempts = 0;
334
335
while (attempts < maxRetries) {
336
try {
337
return session.withTransaction(body);
338
} catch (MongoException e) {
339
attempts++;
340
if (attempts >= maxRetries || !isRetryableError(e)) {
341
throw e;
342
}
343
// Wait before retry
344
try {
345
Thread.sleep(100 * attempts);
346
} catch (InterruptedException ie) {
347
Thread.currentThread().interrupt();
348
throw new RuntimeException(ie);
349
}
350
}
351
}
352
throw new RuntimeException("Max retries exceeded");
353
}
354
```
355
356
### Error Handling in Transactions
357
358
Proper error handling patterns for transactional operations.
359
360
```java { .api }
361
try (ClientSession session = client.startSession()) {
362
session.withTransaction(() -> {
363
try {
364
// Business logic that might fail
365
processPayment(session, paymentInfo);
366
updateOrderStatus(session, orderId, "paid");
367
sendConfirmationEmail(customerEmail);
368
369
return "success";
370
371
} catch (PaymentDeclinedException e) {
372
// Business logic error - should abort transaction
373
updateOrderStatus(session, orderId, "payment_failed");
374
throw new RuntimeException("Payment declined: " + e.getMessage());
375
376
} catch (EmailServiceException e) {
377
// Email failure shouldn't abort financial transaction
378
// Log error but continue
379
logger.warn("Failed to send confirmation email", e);
380
return "success_no_email";
381
382
} catch (MongoWriteException e) {
383
// Database constraint violation
384
logger.error("Database constraint violation", e);
385
throw e; // Will cause transaction retry or abort
386
}
387
});
388
}
389
390
// Handle specific transaction errors
391
try {
392
performTransactionalOperation(session);
393
} catch (MongoTransactionException e) {
394
if (e.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)) {
395
// Retry the entire transaction
396
logger.info("Transient transaction error, retrying...");
397
// Retry logic here
398
} else if (e.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL)) {
399
// Check if transaction actually committed
400
logger.warn("Unknown transaction commit result");
401
// Verification logic here
402
} else {
403
// Permanent failure
404
logger.error("Transaction failed permanently", e);
405
throw e;
406
}
407
}
408
```
409
410
### Performance Considerations
411
412
Guidelines for optimizing transaction performance.
413
414
```java { .api }
415
// Keep transactions short and focused
416
session.withTransaction(() -> {
417
// Good: Quick, focused operations
418
collection.insertOne(session, document);
419
relatedCollection.updateOne(session, filter, update);
420
return null;
421
});
422
423
// Avoid in transactions: Long-running operations
424
session.withTransaction(() -> {
425
// Bad: Don't do this in transactions
426
// - Large bulk operations
427
// - Network calls to external services
428
// - Complex aggregations
429
// - File I/O operations
430
431
// Better: Do these outside the transaction
432
return null;
433
});
434
435
// Batch related operations efficiently
436
List<WriteModel<Document>> operations = Arrays.asList(
437
new InsertOneModel<>(doc1),
438
new UpdateOneModel<>(filter1, update1),
439
new DeleteOneModel<>(filter2)
440
);
441
442
session.withTransaction(() -> {
443
// Efficient: Single bulk operation
444
collection.bulkWrite(session, operations);
445
return null;
446
});
447
448
// Use appropriate read/write concerns
449
TransactionOptions fastTxn = TransactionOptions.builder()
450
.readConcern(ReadConcern.LOCAL) // Faster reads
451
.writeConcern(WriteConcern.W1) // Faster writes
452
.maxCommitTime(5, TimeUnit.SECONDS) // Quick timeout
453
.build();
454
455
TransactionOptions safeTxn = TransactionOptions.builder()
456
.readConcern(ReadConcern.SNAPSHOT) // Consistent reads
457
.writeConcern(WriteConcern.MAJORITY) // Durable writes
458
.maxCommitTime(30, TimeUnit.SECONDS) // Longer timeout
459
.build();
460
```