Locks
This chapter will guide you on how to use the LOCK feature of Kronos.
Add a lock to select
Use lock(...) on a select chain when the generated query should include a pessimistic lock. Calling lock() without arguments uses SqlLock.Update().
update lock
import com.kotlinorm.syntax.statement.SqlLock
val user = User()
.select()
.where { it.id == 1 }
.lock(SqlLock.Update())
.first()mysql
SELECT `id`, `name`
FROM `user`
WHERE `user`.`id` = :id
FOR UPDATEKronos stores the lock on the select task and renders it through the active database dialect. For query fields, conditions, and result methods, see 📚Select and 📚Result Methods.
Use a shared lock
Use SqlLock.Share() when the generated query should request a shared/read lock.
share lock
val users = User()
.select()
.where { it.status == "ACTIVE" }
.lock(SqlLock.Share())
.toList()Shared and update locks are rendered by the SQL dialect. Keep lock usage close to the transaction boundary that needs the locked read.
Regular upsert can use a lock
Regular upsert().on { ... } checks whether a matching row exists before choosing update or insert. The match query uses SqlLock.Update() by default when the optimistic lock strategy is not enabled. Use .lock(...) to make the lock explicit or to set a different lock.
upsert
import com.kotlinorm.syntax.statement.SqlLock
User(id = 1, name = "Kronos")
.upsert { it.name }
.on { it.id }
.lock(SqlLock.Update())
.execute()For conflict-field and update-field examples, see 📚Upsert.
Optimistic locking is a mutation strategy
Optimistic lock behavior is configured through @Version or Kronos.optimisticLockStrategy. It initializes and increments the version field during insert, update, logical delete, and upsert paths.
version
data class Product(
@PrimaryKey(identity = true)
var id: Int? = null,
@Version
var version: Int? = null
) : KPojoFor version-field behavior, see 📚Optimistic Lock and 📚Common Strategy.