or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mddeclarative-transactions.mdindex.mdprogrammatic-transactions.mdtransaction-semantics.md

transaction-semantics.mddocs/

0

# Transaction Semantics and Execution

1

2

Advanced transaction execution with customizable propagation behaviors, exception handling, timeout control, and lambda-style execution patterns.

3

4

## Capabilities

5

6

### TransactionSemantics Enum

7

8

Controls transaction behavior in the presence or absence of existing transactions.

9

10

```java { .api }

11

/**

12

* Enum controlling transaction propagation behavior

13

*/

14

enum TransactionSemantics {

15

16

/**

17

* Throws exception if transaction already exists

18

* Otherwise creates new transaction

19

*/

20

DISALLOW_EXISTING,

21

22

/**

23

* Joins existing transaction or creates new one

24

* Exception handler affects existing transaction differently than new

25

*/

26

JOIN_EXISTING,

27

28

/**

29

* Always creates new transaction

30

* Suspends existing transaction if present, resumes after completion

31

*/

32

REQUIRE_NEW,

33

34

/**

35

* Suspends existing transaction and runs without transaction

36

* No-op if no existing transaction

37

* Exception handler cannot be used with this semantic

38

*/

39

SUSPEND_EXISTING

40

}

41

```

42

43

**Usage Examples:**

44

45

```java

46

import io.quarkus.narayana.jta.QuarkusTransaction;

47

import io.quarkus.narayana.jta.TransactionSemantics;

48

49

@ApplicationScoped

50

public class OrderProcessingService {

51

52

public void processOrderWithAudit(Order order) {

53

// Main processing in existing or new transaction

54

QuarkusTransaction.runner(TransactionSemantics.JOIN_EXISTING)

55

.run(() -> {

56

validateOrder(order);

57

updateInventory(order);

58

chargeCustomer(order);

59

});

60

61

// Audit logging in separate transaction

62

QuarkusTransaction.runner(TransactionSemantics.REQUIRE_NEW)

63

.run(() -> {

64

auditRepository.log("Order processed: " + order.getId());

65

});

66

}

67

68

public void sensitiveOperation() {

69

// Must run without any existing transaction

70

QuarkusTransaction.runner(TransactionSemantics.DISALLOW_EXISTING)

71

.run(() -> {

72

performSecurityCheck();

73

updateSecurityLog();

74

});

75

}

76

77

public void sendNotification(String message) {

78

// Run outside transaction scope entirely

79

QuarkusTransaction.runner(TransactionSemantics.SUSPEND_EXISTING)

80

.run(() -> {

81

emailService.send(message);

82

// This runs without any transaction, even if called

83

// from within a transactional method

84

});

85

}

86

}

87

```

88

89

### TransactionRunner Interface

90

91

Base interface for executing tasks with transaction semantics.

92

93

```java { .api }

94

/**

95

* Interface for running tasks with specific transaction semantics

96

*/

97

interface TransactionRunner {

98

99

/**

100

* Execute runnable with selected transaction semantics

101

* @param task Task to execute

102

*/

103

void run(Runnable task);

104

105

/**

106

* Execute callable with selected transaction semantics

107

* Checked exceptions are wrapped in QuarkusTransactionException

108

* @param task Task to execute

109

* @return Value returned by task

110

* @throws QuarkusTransactionException if task throws checked exception

111

*/

112

<T> T call(Callable<T> task);

113

}

114

```

115

116

### TransactionRunnerOptions Interface

117

118

Enhanced transaction runner with configuration options.

119

120

```java { .api }

121

/**

122

* Builder interface for configuring transaction runners

123

* Extends TransactionRunner so it can execute tasks directly

124

*/

125

interface TransactionRunnerOptions extends TransactionRunner {

126

127

/**

128

* Set transaction timeout for this execution

129

* @param seconds Timeout in seconds, 0 for system default

130

* @return This builder for method chaining

131

* @throws IllegalArgumentException if seconds is negative

132

*/

133

TransactionRunnerOptions timeout(int seconds);

134

135

/**

136

* Set exception handler for controlling commit/rollback behavior

137

* Handler is called when task throws exception to decide transaction fate

138

* Exception is still propagated to caller after handler executes

139

* Cannot be used with SUSPEND_EXISTING semantics

140

*

141

* @param handler Function returning COMMIT or ROLLBACK decision

142

* @return This builder for method chaining

143

*/

144

TransactionRunnerOptions exceptionHandler(

145

Function<Throwable, TransactionExceptionResult> handler

146

);

147

148

// Inherited from TransactionRunner

149

void run(Runnable task);

150

<T> T call(Callable<T> task);

151

}

152

```

153

154

**Usage Examples:**

155

156

```java

157

import io.quarkus.narayana.jta.TransactionExceptionResult;

158

159

@ApplicationScoped

160

public class PaymentProcessor {

161

162

public boolean processPayment(Payment payment) {

163

return QuarkusTransaction.requiringNew()

164

.timeout(30) // 30 second timeout

165

.exceptionHandler(throwable -> {

166

// Custom exception handling logic

167

if (throwable instanceof InsufficientFundsException) {

168

return TransactionExceptionResult.ROLLBACK;

169

} else if (throwable instanceof PaymentWarningException) {

170

return TransactionExceptionResult.COMMIT; // Continue despite warning

171

}

172

return TransactionExceptionResult.ROLLBACK; // Default to rollback

173

})

174

.call(() -> {

175

validatePayment(payment);

176

chargeCard(payment);

177

updateAccount(payment);

178

return true; // Success

179

});

180

}

181

182

public void performBatchOperation(List<Operation> operations) {

183

QuarkusTransaction.joiningExisting()

184

.timeout(300) // 5 minute timeout for batch

185

.run(() -> {

186

for (Operation op : operations) {

187

processOperation(op);

188

}

189

});

190

}

191

}

192

```

193

194

### TransactionExceptionResult Enum

195

196

Controls transaction outcome based on exception handling.

197

198

```java { .api }

199

/**

200

* Decision enum for exception handler results

201

*/

202

enum TransactionExceptionResult {

203

/** Transaction should be committed despite exception */

204

COMMIT,

205

206

/** Transaction should be rolled back due to exception */

207

ROLLBACK

208

}

209

```

210

211

**Advanced Exception Handling:**

212

213

```java

214

@ApplicationScoped

215

public class DataMigrationService {

216

217

public void migrateDataWithRecovery(List<DataRecord> records) {

218

QuarkusTransaction.requiringNew()

219

.exceptionHandler(this::handleMigrationException)

220

.run(() -> {

221

for (DataRecord record : records) {

222

try {

223

migrateRecord(record);

224

} catch (DataCorruptionException e) {

225

logCorruptedRecord(record, e);

226

// Continue with other records

227

}

228

}

229

});

230

}

231

232

private TransactionExceptionResult handleMigrationException(Throwable throwable) {

233

if (throwable instanceof DataCorruptionException) {

234

// Log but don't fail entire batch

235

logger.warn("Data corruption detected", throwable);

236

return TransactionExceptionResult.COMMIT;

237

} else if (throwable instanceof DatabaseConnectionException) {

238

// Critical failure, rollback everything

239

logger.error("Database connection failed", throwable);

240

return TransactionExceptionResult.ROLLBACK;

241

} else if (throwable instanceof ValidationException) {

242

// Business logic error, rollback

243

return TransactionExceptionResult.ROLLBACK;

244

}

245

246

// Default to rollback for unknown exceptions

247

return TransactionExceptionResult.ROLLBACK;

248

}

249

}

250

```

251

252

### Semantic Behavior Details

253

254

#### JOIN_EXISTING Behavior

255

256

```java

257

public void demonstrateJoinExisting() {

258

// Scenario 1: No existing transaction

259

QuarkusTransaction.joiningExisting().run(() -> {

260

// New transaction created

261

// Exception handler affects this transaction directly

262

performWork();

263

});

264

265

// Scenario 2: Called within existing transaction

266

QuarkusTransaction.begin();

267

try {

268

QuarkusTransaction.joiningExisting()

269

.exceptionHandler(ex -> TransactionExceptionResult.ROLLBACK)

270

.run(() -> {

271

// Runs in existing transaction

272

// ROLLBACK result marks existing transaction as rollback-only

273

// COMMIT result takes no action on existing transaction

274

performWork();

275

});

276

QuarkusTransaction.commit(); // May fail if marked rollback-only

277

} catch (Exception e) {

278

QuarkusTransaction.rollback();

279

}

280

}

281

```

282

283

#### REQUIRE_NEW Behavior

284

285

```java

286

public void demonstrateRequireNew() {

287

QuarkusTransaction.begin();

288

try {

289

// This runs in the outer transaction

290

performInitialWork();

291

292

QuarkusTransaction.requiringNew().run(() -> {

293

// This runs in completely separate transaction

294

// Outer transaction is suspended

295

// Success/failure here doesn't affect outer transaction

296

performIndependentWork();

297

});

298

// Outer transaction resumed here

299

300

performFinalWork();

301

QuarkusTransaction.commit();

302

} catch (Exception e) {

303

QuarkusTransaction.rollback();

304

}

305

}

306

```

307

308

#### SUSPEND_EXISTING Behavior

309

310

```java

311

public void demonstrateSuspendExisting() {

312

QuarkusTransaction.begin();

313

try {

314

performTransactionalWork();

315

316

QuarkusTransaction.suspendingExisting().run(() -> {

317

// Runs completely outside any transaction

318

// Cannot use exception handler with this semantic

319

sendEmailNotification();

320

logToExternalSystem();

321

});

322

323

// Original transaction resumed

324

performMoreTransactionalWork();

325

QuarkusTransaction.commit();

326

} catch (Exception e) {

327

QuarkusTransaction.rollback();

328

}

329

}

330

```

331

332

### Timeout Configuration

333

334

```java

335

@ApplicationScoped

336

public class LongRunningOperationService {

337

338

public void performQuickOperation() {

339

QuarkusTransaction.requiringNew()

340

.timeout(10) // 10 seconds

341

.run(() -> {

342

quickDatabaseUpdate();

343

});

344

}

345

346

public void performBatchOperation() {

347

QuarkusTransaction.requiringNew()

348

.timeout(600) // 10 minutes

349

.run(() -> {

350

processBatchRecords();

351

});

352

}

353

354

public void performOperationWithDefaultTimeout() {

355

QuarkusTransaction.requiringNew()

356

.timeout(0) // Use system default timeout

357

.run(() -> {

358

performStandardOperation();

359

});

360

}

361

}

362

```

363

364

## Best Practices

365

366

### Choosing Transaction Semantics

367

368

```java

369

// ✅ Use REQUIRE_NEW for independent operations (auditing, logging)

370

QuarkusTransaction.requiringNew().run(() -> {

371

auditRepository.log("Operation completed");

372

});

373

374

// ✅ Use JOIN_EXISTING for operations that should be part of caller's transaction

375

QuarkusTransaction.joiningExisting().run(() -> {

376

updateRelatedData();

377

});

378

379

// ✅ Use SUSPEND_EXISTING for non-transactional operations (external APIs)

380

QuarkusTransaction.suspendingExisting().run(() -> {

381

callExternalAPI();

382

});

383

384

// ✅ Use DISALLOW_EXISTING for operations that must start fresh

385

QuarkusTransaction.disallowingExisting().run(() -> {

386

initializeSystemState();

387

});

388

```

389

390

### Exception Handler Guidelines

391

392

```java

393

// ✅ Good: Clear exception handling logic

394

.exceptionHandler(throwable -> {

395

if (throwable instanceof BusinessWarningException) {

396

logger.warn("Warning during processing", throwable);

397

return TransactionExceptionResult.COMMIT;

398

}

399

return TransactionExceptionResult.ROLLBACK;

400

})

401

402

// ❌ Avoid: Side effects in exception handler

403

.exceptionHandler(throwable -> {

404

// Don't do heavy work in exception handler

405

sendEmailAlert(); // ❌ Bad

406

return TransactionExceptionResult.ROLLBACK;

407

})

408

409

// ✅ Good: Exception handler focuses on transaction decision only

410

.exceptionHandler(throwable -> {

411

// Keep it simple and fast

412

return throwable instanceof WarningException ?

413

TransactionExceptionResult.COMMIT :

414

TransactionExceptionResult.ROLLBACK;

415

})

416

```

417

418

### Performance Considerations

419

420

```java

421

// ✅ Prefer declarative transactions for simple cases

422

@Transactional

423

public void simpleOperation() { }

424

425

// ✅ Use programmatic for complex logic

426

public void complexOperation() {

427

QuarkusTransaction.joiningExisting()

428

.timeout(customTimeout)

429

.exceptionHandler(this::handleComplexExceptions)

430

.run(() -> {

431

// Complex transaction logic

432

});

433

}

434

```