or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

change-streams.mdcollection-crud.mdconnection-management.mddatabase-operations.mdencryption.mdgridfs.mdindex-management.mdindex.mdquery-aggregation.mdsessions-transactions.md

sessions-transactions.mddocs/

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

```