60 lines
2.4 KiB
Markdown
60 lines
2.4 KiB
Markdown
---
|
|
type: Guide
|
|
status: DRAFT
|
|
owner: Backend Developer
|
|
date: 2026-02-02
|
|
last_update: 2026-03-15
|
|
---
|
|
|
|
# Database Best Practices & Exposed 1.0.0
|
|
|
|
Dieser Guide beschreibt den korrekten Umgang mit der Datenbank-Schicht in unseren Backend-Services, basierend auf JetBrains Exposed 1.0.0.
|
|
|
|
## 1. Architektur-Prinzipien
|
|
|
|
* **Trennung:** Datenbank-Zugriffe gehören ausschließlich in die `infrastructure/persistence` Schicht. Services nutzen Repositories (Interfaces), keine direkten Exposed-Aufrufe.
|
|
* **Transaktionen:** Jede geschäftliche Operation sollte in einer Transaktion laufen. Nutze dafür die Helper aus `DatabaseUtils.kt`.
|
|
|
|
## 2. Nutzung von `DatabaseUtils`
|
|
|
|
Wir haben zentrale Wrapper für Transaktionen, um Fehlerbehandlung und Logging zu vereinheitlichen.
|
|
|
|
### 2.1 Transaktionen starten
|
|
|
|
Nutze immer `transactionResult` (oder die Aliase `readTransaction` / `writeTransaction`), um Exposed-Code auszuführen.
|
|
|
|
```kotlin
|
|
fun findUser(id: UUID): Result<User> = readTransaction {
|
|
// 'this' ist hier eine JdbcTransaction
|
|
UserTable.select { UserTable.id eq id }
|
|
.map { /* row -> User(...) */ }
|
|
.singleOrNull()
|
|
}
|
|
```
|
|
|
|
**Wichtig:** Der Lambda-Receiver ist `JdbcTransaction`. Das ermöglicht Zugriff auf Low-Level JDBC Funktionen, falls nötig.
|
|
|
|
### 2.2 Low-Level SQL (`exec`, `executeUpdate`)
|
|
|
|
Vermeide rohes SQL, wo immer möglich. Wenn es sein muss (z.B. für Performance-Optimierungen oder spezielle Postgres-Features), beachte folgende Regeln für Exposed 1.0.0:
|
|
|
|
* **`exec`:** Nutze immer `explicitStatementType`.
|
|
```kotlin
|
|
this.exec("SELECT 1", explicitStatementType = StatementType.SELECT) { rs -> /* handle ResultSet */ }
|
|
```
|
|
* **`executeUpdate`:** Nutze die Helper-Methode `DatabaseUtils.executeUpdate`, da sie sich um das korrekte Schließen von Statements kümmert (Exposed `PreparedStatementApi` ist nicht `AutoCloseable`).
|
|
|
|
## 3. Exposed 1.0.0 Besonderheiten
|
|
|
|
* **UUIDs:** Nutze `Table.javaUUID()` für `java.util.UUID` Spalten. `Table.uuid()` ist für `kotlin.uuid.Uuid` reserviert.
|
|
* **JSONB:** Bei SQLite wird JSON automatisch gewrappt. Prüfe `castToJsonFormat` Flag.
|
|
|
|
## 4. Fehlerbehandlung
|
|
|
|
`DatabaseUtils` fängt `SQLException` ab und mappt sie auf unsere Domain-Fehler (`ErrorDto`):
|
|
* Duplicate Key -> `ErrorCodes.DUPLICATE_ENTRY`
|
|
* Foreign Key -> `ErrorCodes.FOREIGN_KEY_VIOLATION`
|
|
* Timeout -> `ErrorCodes.DATABASE_TIMEOUT`
|
|
|
|
Wirf keine rohen Exceptions aus Repositories.
|