Parametrisierte Abfragen und Transaktionen
Übergeben Sie Parameter sicher und verwalten Sie mehrstufige Datenbanktransaktionen in R.
Parametrisierte Abfragen und Transaktionen ist eine kostenlose R Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des R Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der R Academy-Kurs umfasst insgesamt 4 Lektionen.
Warum parametrisierte Abfragen?
Wenn Benutzereingaben direkt in eine SQL-Zeichenkette eingefügt werden, kann ein Angreifer schädlichen SQL-Code einschleusen. Parametrisierte Abfragen trennen die SQL-Struktur von den Datenwerten. Dadurch werden Injection-Angriffe verhindert und der Code wird übersichtlicher und leichter lesbar.
library(DBI)
# DANGEROUS: string concatenation (SQL injection risk!)
user_input <- "'; DROP TABLE users; --"
# bad_sql <- paste0("SELECT * FROM users WHERE name = '", user_input, "'")
# dbGetQuery(con, bad_sql) <- NEVER do this
# SAFE: parameterized query
# dbGetQuery(con, 'SELECT * FROM users WHERE name = $1',
# params = list(user_input))
cat('Parameterized queries prevent SQL injection')dbGetQuery() mit Parametern
dbGetQuery() führt eine SELECT-Anweisung aus und gibt die Ergebnisse als Dataframe zurück. Übergeben Sie eine params-Liste, um Werte an Platzhalter zu binden. Die Syntax der Platzhalter hängt vom Treiber ab: $1 für PostgreSQL, ? für SQLite/MySQL.
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
dbWriteTable(con, 'employees', data.frame(
name = c('Alice', 'Bob', 'Carol'),
department = c('Engineering', 'Marketing', 'Engineering'),
salary = c(90000, 75000, 95000)
))
# Parameterized SELECT — SQLite uses ?
result <- dbGetQuery(
con,
'SELECT name, salary FROM employees WHERE department = ?',
params = list('Engineering')
)
print(result)
dbDisconnect(con)dbExecute() – INSERT, UPDATE, DELETE
dbExecute() führt SQL-Anweisungen aus, die Daten ändern (INSERT, UPDATE, DELETE), und gibt die Anzahl der betroffenen Zeilen zurück. Verwenden Sie params für eine sichere Wertebindung. Dies ist die richtige Funktion für Schreibvorgänge.
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
dbWriteTable(con, 'users', data.frame(
id = 1:3,
name = c('Alice', 'Bob', 'Carol'),
active = c(TRUE, FALSE, TRUE)
))
# Safe UPDATE with parameters
rows_affected <- dbExecute(
con,
'UPDATE users SET active = ? WHERE id = ?',
params = list(TRUE, 2)
)
cat('Rows updated:', rows_affected, '\n')
# Verify
result <- dbGetQuery(con, 'SELECT * FROM users WHERE id = 2')
cat('Bob active:', result$active)
dbDisconnect(con)Mehrere Parameter in einer Abfrage
Sie können mehrere Parameter binden, indem Sie sie alle in der params-Liste angeben. Sie werden der Reihe nach an die Platzhalter (? oder $1, $2, ...) in der SQL-Zeichenkette gebunden. Stimmen Sie die Anzahl der Listenelemente immer mit der Anzahl der Platzhalter ab.
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
dbWriteTable(con, 'products', data.frame(
id = 1:4,
name = c('Apple', 'Banana', 'Cherry', 'Date'),
price = c(1.5, 0.8, 3.0, 5.0),
stock = c(100, 200, 50, 30)
))
# Filter by two parameters
result <- dbGetQuery(
con,
'SELECT name, price FROM products WHERE price > ? AND stock > ?',
params = list(1.0, 40)
)
print(result)
dbDisconnect(con)Parametrisierter INSERT
Parametrisierte INSERT-Anweisungen fügen sicher neue Datensätze hinzu. Binden Sie den Wert jeder Spalte als Parameter. Verwenden Sie für Masseneinfügungen stattdessen dbAppendTable() mit einem Dataframe – das ist schneller, und DBI übernimmt die Bindung automatisch.
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
dbExecute(con, 'CREATE TABLE logs (level TEXT, message TEXT, ts TEXT)')
# Parameterized INSERT
dbExecute(
con,
'INSERT INTO logs (level, message, ts) VALUES (?, ?, ?)',
params = list('INFO', 'User logged in', as.character(Sys.time()))
)
result <- dbGetQuery(con, 'SELECT * FROM logs')
print(result)
dbDisconnect(con)dbBegin() und dbCommit() – Transaktionen
Eine Transaktion fasst mehrere SQL-Anweisungen zu einer atomaren Einheit zusammen: Entweder sind alle erfolgreich, oder keine wird ausgeführt. Verwenden Sie dbBegin() zum Starten und anschließend dbCommit(), um alle Änderungen gemeinsam abzuschließen.
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
dbExecute(con, 'CREATE TABLE accounts (id INTEGER, balance REAL)')
dbExecute(con, "INSERT INTO accounts VALUES (1, 1000), (2, 500)")
# Transfer 200 from account 1 to account 2
dbBegin(con)
dbExecute(con, 'UPDATE accounts SET balance = balance - ? WHERE id = ?',
params = list(200, 1))
dbExecute(con, 'UPDATE accounts SET balance = balance + ? WHERE id = ?',
params = list(200, 2))
dbCommit(con)
result <- dbGetQuery(con, 'SELECT * FROM accounts')
print(result)
dbDisconnect(con)dbRollback() – Eine Transaktion rückgängig machen
Wenn eine Anweisung in einer Transaktion fehlschlägt, rufen Sie dbRollback() auf, um alle seit dbBegin() vorgenommenen Änderungen rückgängig zu machen. Dadurch bleibt die Datenbank in einem konsistenten Zustand. Kombinieren Sie dbBegin() immer mit entweder dbCommit() oder dbRollback().
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
dbExecute(con, 'CREATE TABLE orders (id INTEGER, amount REAL)')
dbExecute(con, 'INSERT INTO orders VALUES (1, 500)')
# Simulate a failed transaction
dbBegin(con)
tryCatch({
dbExecute(con, 'UPDATE orders SET amount = ? WHERE id = ?',
params = list(600, 1))
stop('Simulated error during processing') # something goes wrong
dbCommit(con)
}, error = function(e) {
dbRollback(con)
cat('Transaction rolled back:', e$message, '\n')
})
# Amount is still 500 (rollback worked)
result <- dbGetQuery(con, 'SELECT * FROM orders')
cat('Amount after rollback:', result$amount)
dbDisconnect(con)dbWithTransaction() – Das sicherere Muster
dbWithTransaction() führt Ihren Codeblock automatisch innerhalb einer Transaktion aus. Bei erfolgreicher Ausführung des Blocks wird ein Commit durchgeführt; tritt ein Fehler auf, erfolgt ein Rollback. Das ist übersichtlicher und weniger fehleranfällig als der manuelle Aufruf von dbBegin() / dbCommit() / dbRollback().
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
dbExecute(con, 'CREATE TABLE ledger (account TEXT, amount REAL)')
dbExecute(con, "INSERT INTO ledger VALUES ('Alice', 1000), ('Bob', 500)")
# Automatic transaction management:
dbWithTransaction(con, {
dbExecute(con, "UPDATE ledger SET amount = amount - 100 WHERE account = 'Alice'",
params = list())
dbExecute(con, "UPDATE ledger SET amount = amount + 100 WHERE account = 'Bob'",
params = list())
})
# Committed automatically on success
print(dbGetQuery(con, 'SELECT * FROM ledger'))
dbDisconnect(con)Fehlerbehandlung innerhalb von Transaktionen
Die Kombination aus tryCatch() und dbWithTransaction() ermöglicht eine übersichtliche Fehlerberichterstattung. Wenn im inneren Block ein Fehler ausgelöst wird, führt dbWithTransaction() automatisch ein Rollback durch, und Ihre Fehlerbehandlung kann das Problem protokollieren oder erneut auslösen.
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
dbExecute(con, 'CREATE TABLE inventory (item TEXT, qty INTEGER)')
dbExecute(con, "INSERT INTO inventory VALUES ('Widget', 100)")
safe_update <- function(con, item, qty_change) {
tryCatch(
dbWithTransaction(con, {
dbExecute(con,
'UPDATE inventory SET qty = qty + ? WHERE item = ?',
params = list(qty_change, item))
cat('Updated', item, 'by', qty_change, '\n')
}),
error = function(e) cat('Failed (rolled back):', e$message, '\n')
)
}
safe_update(con, 'Widget', -30)
print(dbGetQuery(con, 'SELECT * FROM inventory'))
dbDisconnect(con)Batch-Einfügungen für bessere Leistung
Viele Zeilen einzeln in einer Schleife einzufügen, ist langsam. Zwei bessere Ansätze sind: Verwenden Sie dbAppendTable(), um einen ganzen Dataframe auf einmal einzufügen, oder fassen Sie einzelne Einfügungen in einer einzigen Transaktion zusammen – Datenbanken schreiben die Änderungen dann erst am Ende auf die Festplatte, wodurch Masseneinfügungen innerhalb einer Transaktion deutlich schneller sind als Einfügungen mit Auto-Commit.
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
dbExecute(con, 'CREATE TABLE events (user_id INTEGER, action TEXT)')
# Fast: insert a whole data frame at once
new_events <- data.frame(
user_id = c(101, 102, 103, 104),
action = c('login', 'view', 'purchase', 'logout')
)
dbAppendTable(con, 'events', new_events)
result <- dbGetQuery(con, 'SELECT COUNT(*) AS n FROM events')
cat('Rows inserted:', result$n)
dbDisconnect(con)dbDisconnect() – Verbindungen immer schließen
Datenbankverbindungen verbrauchen Ressourcen auf dem Server. Rufen Sie immer dbDisconnect(con) auf, wenn Sie fertig sind. Wenn Sie am Anfang einer Funktion on.exit(dbDisconnect(con)) verwenden, wird sichergestellt, dass die Verbindung auch bei einem Fehler geschlossen wird.
library(DBI)
# Pattern: use on.exit to guarantee disconnection
run_query <- function(sql) {
con <- dbConnect(RSQLite::SQLite(), ':memory:')
on.exit(dbDisconnect(con), add = TRUE) # always runs
dbExecute(con, 'CREATE TABLE t (x INTEGER)')
dbExecute(con, 'INSERT INTO t VALUES (1), (2), (3)')
result <- dbGetQuery(con, sql)
result # con is closed automatically after return
}
df <- run_query('SELECT * FROM t WHERE x > 1')
cat('Rows:', nrow(df))
# on.exit fires after return — connection cleanly closedKurzer Wissenstest
Sie müssen zwei zusammengehörige UPDATE-Anweisungen so gruppieren, dass entweder beide erfolgreich sind oder keine Änderung an der Datenbank vorgenommen wird. Welcher Ansatz ist am besten geeignet?
Parametrisierte Abfragen und Transaktionen – Die wichtigsten Punkte
Sichere und zuverlässige Datenbankoperationen in R mit DBI:
- Fügen Sie Benutzereingaben niemals durch Verkettung in SQL-Zeichenketten ein – verwenden Sie immer
params dbGetQuery(con, sql, params = list(...))– sichere SELECT-AbfragedbExecute(con, sql, params = list(...))– sicheres INSERT/UPDATE/DELETE- Platzhalter:
?für SQLite/MySQL,$1/$2für PostgreSQL dbBegin()+dbCommit()+dbRollback()– manuelle TransaktionssteuerungdbWithTransaction(con, { ... })– automatischer Commit/Rollback (bevorzugt)dbAppendTable(con, 'tbl', df)– schnelle Masseneinfügungon.exit(dbDisconnect(con))– Verbindungen immer schließen
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ':memory:')
on.exit(dbDisconnect(con), add = TRUE)
dbExecute(con, 'CREATE TABLE transfers (from_id INT, to_id INT, amount REAL)')
# Safe parameterized insert inside a transaction:
dbWithTransaction(con, {
dbExecute(con,
'INSERT INTO transfers (from_id, to_id, amount) VALUES (?, ?, ?)',
params = list(1, 2, 250.00)
)
})
result <- dbGetQuery(con, 'SELECT * FROM transfers')
cat('Transfer recorded:', result$amount)Lerne R mit einem KI-Tutor — kostenlos
Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.
- Kurse
- 43
- Lektionen
- 159
Häufig gestellte Fragen
Ist die Lektion „Parametrisierte Abfragen und Transaktionen“ kostenlos?
Ja — der vollständige Text von „Parametrisierte Abfragen und Transaktionen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des R Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der R Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Parametrisierte Abfragen und Transaktionen“?
Übergeben Sie Parameter sicher und verwalten Sie mehrstufige Datenbanktransaktionen in R. Du übst R Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um R Academy zu starten?
Keine Vorkenntnisse erforderlich. R Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Parametrisierte Abfragen und Transaktionen“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser R Academy-Lektion Code schreiben und ausführen?
Ja. Jede R Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Grundlagen von DBI und RSQLite
- Mit PostgreSQL und MySQL verbinden
- dbplyr: SQL über dplyr-Syntax
- Parametrisierte Abfragen und Transaktionen