or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

column-adapters.mddatabase-driver.mdindex.mdlogging-debugging.mdquery-execution.mdschema-management.mdtransaction-management.md

transaction-management.mddocs/

0

# Transaction Management

1

2

Comprehensive transaction management system supporting nested transactions, rollback semantics, lifecycle callbacks, and both synchronous and asynchronous execution patterns.

3

4

## Capabilities

5

6

### Transacter Interface

7

8

Main interface for synchronous transaction management.

9

10

```kotlin { .api }

11

/**

12

* A transaction-aware SqlDriver wrapper which can begin a Transaction on the current connection

13

*/

14

interface Transacter : TransacterBase {

15

/**

16

* Starts a Transaction and runs bodyWithReturn in that transaction

17

* @param noEnclosing If true, throws IllegalStateException if there's already an active transaction

18

* @param bodyWithReturn Lambda executed within the transaction context

19

* @return The result returned by bodyWithReturn

20

* @throws IllegalStateException if noEnclosing is true and there is already an active Transaction

21

*/

22

fun <R> transactionWithResult(

23

noEnclosing: Boolean = false,

24

bodyWithReturn: TransactionWithReturn<R>.() -> R

25

): R

26

27

/**

28

* Starts a Transaction and runs body in that transaction

29

* @param noEnclosing If true, throws IllegalStateException if there's already an active transaction

30

* @param body Lambda executed within the transaction context

31

* @throws IllegalStateException if noEnclosing is true and there is already an active Transaction

32

*/

33

fun transaction(

34

noEnclosing: Boolean = false,

35

body: TransactionWithoutReturn.() -> Unit

36

)

37

}

38

```

39

40

### SuspendingTransacter Interface

41

42

Asynchronous version of Transacter supporting coroutine-based transaction management.

43

44

```kotlin { .api }

45

/**

46

* A transaction-aware SqlDriver wrapper which can begin a Transaction on the current connection

47

*/

48

interface SuspendingTransacter : TransacterBase {

49

/**

50

* Starts a Transaction and runs bodyWithReturn in that transaction

51

* @param noEnclosing If true, throws IllegalStateException if there's already an active transaction

52

* @param bodyWithReturn Suspending lambda executed within the transaction context

53

* @return The result returned by bodyWithReturn

54

*/

55

suspend fun <R> transactionWithResult(

56

noEnclosing: Boolean = false,

57

bodyWithReturn: suspend SuspendingTransactionWithReturn<R>.() -> R

58

): R

59

60

/**

61

* Starts a Transaction and runs body in that transaction

62

* @param noEnclosing If true, throws IllegalStateException if there's already an active transaction

63

* @param body Suspending lambda executed within the transaction context

64

*/

65

suspend fun transaction(

66

noEnclosing: Boolean = false,

67

body: suspend SuspendingTransactionWithoutReturn.() -> Unit

68

)

69

}

70

```

71

72

### Transaction Context Interfaces

73

74

Interfaces available within transaction lambda scopes providing rollback and callback capabilities.

75

76

```kotlin { .api }

77

/**

78

* Transaction context for operations that return values

79

*/

80

interface TransactionWithReturn<R> : TransactionCallbacks {

81

/**

82

* Rolls back this transaction and returns the specified value

83

* @param returnValue Value to return after rollback

84

*/

85

fun rollback(returnValue: R): Nothing

86

87

/**

88

* Begin an inner transaction

89

* @param body Lambda executed within the nested transaction context

90

* @return Result of the nested transaction

91

*/

92

fun <R> transaction(body: TransactionWithReturn<R>.() -> R): R

93

}

94

95

/**

96

* Transaction context for operations that don't return values

97

*/

98

interface TransactionWithoutReturn : TransactionCallbacks {

99

/**

100

* Rolls back this transaction

101

*/

102

fun rollback(): Nothing

103

104

/**

105

* Begin an inner transaction

106

* @param body Lambda executed within the nested transaction context

107

*/

108

fun transaction(body: TransactionWithoutReturn.() -> Unit)

109

}

110

111

/**

112

* Suspending transaction context for operations that return values

113

*/

114

interface SuspendingTransactionWithReturn<R> : TransactionCallbacks {

115

/**

116

* Rolls back this transaction and returns the specified value

117

* @param returnValue Value to return after rollback

118

*/

119

fun rollback(returnValue: R): Nothing

120

121

/**

122

* Begin an inner transaction

123

* @param body Suspending lambda executed within the nested transaction context

124

* @return Result of the nested transaction

125

*/

126

suspend fun <R> transaction(body: suspend SuspendingTransactionWithReturn<R>.() -> R): R

127

}

128

129

/**

130

* Suspending transaction context for operations that don't return values

131

*/

132

interface SuspendingTransactionWithoutReturn : TransactionCallbacks {

133

/**

134

* Rolls back this transaction

135

*/

136

fun rollback(): Nothing

137

138

/**

139

* Begin an inner transaction

140

* @param body Suspending lambda executed within the nested transaction context

141

*/

142

suspend fun transactionWithResult(body: suspend SuspendingTransactionWithoutReturn.() -> Unit)

143

}

144

```

145

146

### Transaction Callbacks

147

148

Interface for registering post-commit and post-rollback lifecycle hooks.

149

150

```kotlin { .api }

151

/**

152

* Interface for registering transaction lifecycle callbacks

153

*/

154

interface TransactionCallbacks {

155

/**

156

* Queues function to be run after this transaction successfully commits

157

* @param function Lambda to execute after successful commit

158

*/

159

fun afterCommit(function: () -> Unit)

160

161

/**

162

* Queues function to be run after this transaction rolls back

163

* @param function Lambda to execute after rollback

164

*/

165

fun afterRollback(function: () -> Unit)

166

}

167

```

168

169

### Transaction Implementation Classes

170

171

Base classes for implementing transaction management functionality.

172

173

```kotlin { .api }

174

/**

175

* Base implementation class for synchronous transaction management

176

*/

177

abstract class TransacterImpl(driver: SqlDriver) :

178

BaseTransacterImpl(driver),

179

Transacter

180

181

/**

182

* Base implementation class for asynchronous transaction management

183

*/

184

abstract class SuspendingTransacterImpl(driver: SqlDriver) :

185

BaseTransacterImpl(driver),

186

SuspendingTransacter

187

188

/**

189

* Common base functionality for both synchronous and asynchronous transacter implementations

190

*/

191

abstract class BaseTransacterImpl(protected val driver: SqlDriver) {

192

/**

193

* For internal use, notifies the listeners that their underlying result set has changed

194

* @param identifier Query identifier for listener notification

195

* @param tableProvider Lambda that provides table names to notify

196

*/

197

protected fun notifyQueries(identifier: Int, tableProvider: ((String) -> Unit) -> Unit)

198

199

/**

200

* For internal use, creates a string in the format (?, ?, ?) where there are count question marks

201

* @param count Number of parameters

202

* @return Formatted parameter string

203

*/

204

protected fun createArguments(count: Int): String

205

}

206

```

207

208

**Usage Examples:**

209

210

```kotlin

211

import app.cash.sqldelight.Transacter

212

import app.cash.sqldelight.TransacterImpl

213

import app.cash.sqldelight.db.SqlDriver

214

215

// Implement a database class with transaction support

216

class UserDatabase(driver: SqlDriver) : TransacterImpl(driver) {

217

218

// Simple transaction without return value

219

fun deleteInactiveUsers() {

220

transaction {

221

// These operations happen atomically

222

execute("DELETE FROM user_sessions WHERE user_id IN (SELECT id FROM users WHERE active = 0)")

223

execute("DELETE FROM users WHERE active = 0")

224

225

// Register cleanup after successful commit

226

afterCommit {

227

println("Inactive users deleted successfully")

228

clearCache()

229

}

230

231

// Register error handling after rollback

232

afterRollback {

233

println("Failed to delete inactive users")

234

}

235

}

236

}

237

238

// Transaction with return value

239

fun transferMoney(fromUserId: Long, toUserId: Long, amount: Double): Boolean {

240

return transactionWithResult {

241

val fromBalance = getBalance(fromUserId)

242

val toBalance = getBalance(toUserId)

243

244

// Check sufficient funds

245

if (fromBalance < amount) {

246

rollback(false) // Rollback and return false

247

}

248

249

// Update balances

250

updateBalance(fromUserId, fromBalance - amount)

251

updateBalance(toUserId, toBalance + amount)

252

253

// Log the transaction

254

insertTransactionLog(fromUserId, toUserId, amount)

255

256

afterCommit {

257

sendNotification(fromUserId, "Money transferred successfully")

258

sendNotification(toUserId, "Money received")

259

}

260

261

true // Return success

262

}

263

}

264

265

// Nested transactions

266

fun createUserWithProfile(name: String, email: String, profileData: Map<String, String>): Long {

267

return transactionWithResult {

268

// Create user in outer transaction

269

val userId = insertUser(name, email)

270

271

// Create profile in nested transaction

272

transaction {

273

insertProfile(userId, profileData)

274

275

// If profile creation fails, both user and profile creation will be rolled back

276

// due to nested transaction semantics

277

}

278

279

userId

280

}

281

}

282

283

// Prevent nested transactions

284

fun criticalOperation() {

285

transaction(noEnclosing = true) {

286

// This will throw IllegalStateException if called within another transaction

287

performCriticalDatabaseUpdate()

288

}

289

}

290

}

291

292

// Asynchronous transaction management

293

class AsyncUserDatabase(driver: SqlDriver) : SuspendingTransacterImpl(driver) {

294

295

suspend fun processUserDataAsync(userId: Long): ProcessingResult {

296

return transactionWithResult {

297

val userData = fetchUserData(userId)

298

val processedData = processData(userData) // Suspending function

299

300

updateUserData(userId, processedData)

301

302

ProcessingResult.Success(processedData)

303

}

304

}

305

306

suspend fun batchUpdateUsersAsync(updates: List<UserUpdate>) {

307

transaction {

308

for (update in updates) {

309

updateUser(update.userId, update.data)

310

delay(10) // Suspending operation

311

}

312

313

afterCommit {

314

notifyBatchUpdateComplete()

315

}

316

}

317

}

318

}

319

```

320

321

### Thread Safety and Lifecycle

322

323

- **Transactions** are confined to their creation thread and must not escape the transaction lambda scope

324

- **Nested transactions** inherit the parent transaction's thread context

325

- **Rollback propagation** from inner transactions affects the entire transaction tree

326

- **Callback execution** happens synchronously after transaction completion

327

- **Error handling** during callbacks can create composite exceptions that preserve both original and callback errors