Transaction Context
Context for executing database operations within a transaction.
All operations performed through this context share the same database connection, ensuring they participate in the same transaction. The transaction is committed if all operations succeed, or rolled back if any operation throws an exception.
Basic Usage
stormify.transaction {
val user = create(User(email = "test@example.com"))
create(Profile(userId = user.id, name = "Test User"))
update(account)
}Nested Transactions
Nested transactions are implemented using database savepoints:
stormify.transaction {
create(record1)
transaction { // Creates a savepoint
create(record2)
// If this fails, only record2 is rolled back
}
create(record3) // Still executes
}Extracting Complex Logic
Pattern 1: Extension Functions (Recommended)
Define extension functions on TransactionContext for clean, reusable business logic:
fun TransactionContext.registerUser(email: String, name: String) {
val user = create(User(email = email))
create(Profile(userId = user.id, name = name))
create(AuditLog(action = "User registered", userId = user.id))
}
fun TransactionContext.transferFunds(from: Account, to: Account, amount: Double) {
require(from.balance >= amount) { "Insufficient funds" }
update(from.copy(balance = from.balance - amount))
update(to.copy(balance = to.balance + amount))
create(Transaction(fromId = from.id, toId = to.id, amount = amount))
}
// Usage
stormify.transaction {
registerUser("alice@example.com", "Alice")
transferFunds(accountA, accountB, 100.0)
}Pattern 2: Service Layer Classes
Encapsulate transaction logic in service classes for structured applications:
class UserService(private val tx: TransactionContext) {
fun registerUser(email: String, name: String) {
val user = tx.create(User(email = email))
tx.create(Profile(userId = user.id, name = name))
}
fun deleteUser(userId: Int) {
val user = tx.findById<User>(userId)
tx.delete(user)
}
}
// Usage
stormify.transaction {
val service = UserService(this)
service.registerUser("alice@example.com", "Alice")
}See also
Functions
Executes an SQL UPDATE/INSERT/DELETE and returns the number of affected rows.
Finds all entities of type T, optionally filtered by a whereClause.
Finds all entities of kclass, optionally filtered by a whereClause.
Type-safe variant of getDetails that accepts an annotation-processor-generated reference path (e.g. Paths.AuditEntry_.createdBy) instead of a string.
Retrieves all detail (child) entities of detailsClass related to a parent through a foreign key.
Executes a nested transaction using a database savepoint.