一键导入
exposed-jdbc-v1
Exposed 1.0.0 JDBC DSL patterns (imports, transactions, queries, raw SQL, and types)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Exposed 1.0.0 JDBC DSL patterns (imports, transactions, queries, raw SQL, and types)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Gi nye apper tilgang til Lumi feedback — ruter Azure via proxy og TokenX direkte til API
Database migration patterns using Flyway with versioned SQL scripts
Sealed class configuration pattern for Kotlin applications with environment-specific settings
Setting up Prometheus metrics, OpenTelemetry tracing, and health endpoints for Nais applications
Responsive layout patterns using Aksel spacing tokens with Box, VStack, HStack, and HGrid
Observability setup for lumi-dashboard (TanStack Start/Node.js) on Nais
| name | exposed-jdbc-v1 |
| description | Exposed 1.0.0 JDBC DSL patterns (imports, transactions, queries, raw SQL, and types) |
Use these conventions when working with Exposed 1.0.0 (JDBC) in Kotlin services.
org.jetbrains.exposed.v1.core.* for core DSL types and expressions.org.jetbrains.exposed.v1.jdbc.* for JDBC-only functions (selectAll, insert, update, deleteWhere, SchemaUtils, Database).org.jetbrains.exposed.v1.javatime.* (or kotlin-datetime) for date/time columns.SqlExpressionBuilder.run { ... } patterns; import top-level ops from v1.core.import org.jetbrains.exposed.v1.jdbc.Database
val db = Database.connect(dataSource)
Prefer a pooled DataSource (HikariCP) and store the Database instance for reuse. Avoid calling Database.connect() multiple times per DB.
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
val rows = transaction(db) {
Table.selectAll().where { Table.id eq id }.toList()
}
transaction {}.transaction(db) when multiple databases are present or when explicitness helps.Prefer a shared suspend helper that uses Exposed v1 suspendTransaction and exposes a Transaction receiver:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jetbrains.exposed.v1.core.Transaction
import org.jetbrains.exposed.v1.jdbc.transactions.suspendTransaction
suspend fun <T> dbQuery(block: suspend Transaction.() -> T): T {
return withContext(Dispatchers.IO) {
suspendTransaction(DatabaseHolder.database) { block() }
}
}
dbQuery { ... }.Database.connect(...) is called once at startup and reused (e.g. via a DatabaseHolder).Use exec(...) with typed parameters and a ResultSet mapper:
import org.jetbrains.exposed.v1.core.VarCharColumnType
import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager
val sql = "SELECT name FROM users WHERE team = ?"
val transaction = TransactionManager.current()
transaction.exec(sql, listOf(VarCharColumnType() to team)) { rs ->
val names = mutableListOf<String>()
while (rs.next()) names += rs.getString("name")
names
} ?: emptyList()
javaUUID("id") for java.util.UUID (avoids kotlin.uuid.ExperimentalUuidApi).uuid("id") only if you intentionally want kotlin.uuid.Uuid.import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.core.java.javaUUID
object ExampleTable : Table("example") {
val id = javaUUID("id").autoGenerate()
}
Use custom ColumnType for PostgreSQL-specific types if needed, and keep it close to the table definition.
For JSONB, consider exposed-json if you want typed JSON with serializers.
Use Flyway for production migrations. Avoid SchemaUtils.create() except in tests or temporary tooling.
If a migration uses CREATE INDEX CONCURRENTLY, avoid running it as-is in tests (it can hang or fail under Testcontainers).
Use a Flyway placeholder so tests can disable the keyword:
CREATE INDEX ${concurrently} IF NOT EXISTS idx_name ON table_name (col);
Flyway.configure()
.placeholders(mapOf("concurrently" to "CONCURRENTLY")) // prod
.load()
.migrate()
Flyway.configure()
.placeholders(mapOf("concurrently" to "")) // tests
.load()
.migrate()
DatabaseHolder.database must be connected before any dbQuery {} calls; enforce this in app startup and tests.Database instance to avoid stale connections.