better-duck-core drives
transactions with plain SQL (BEGIN TRANSACTION / COMMIT / ROLLBACK) through
execute_batch. Three ergonomic styles are
offered on Connection, each a different trade-off.
Closure scope (recommended)
transaction<T, F: FnOnce(&mut Connection) -> Result<T>>(&mut self, f) -> Result<T> runs a closure
inside a transaction: BEGIN, then COMMIT on Ok or ROLLBACK on Err.
RAII guard
begin_transaction(&mut self) -> Result<Transaction<'_>> returns a better_duck_core::Transaction
guard that derefs to the Connection and rolls back on drop unless committed. This is what
makes the ?-early-return path safe without a closure.
commit(self) -> Result<()>androllback(self) -> Result<()>consume the guard.- Dropping the guard without either does a best-effort rollback.
Low-level verbs
begin(), commit(), and rollback() on Connection issue the raw statements directly when you
need manual control.
The transaction! macro
With the derive feature, transaction!(conn, { … }) is a terser scope that commits on Ok and
rolls back on Err or panic. It works for both the core Connection and a Diesel
DuckDbConnection (both expose transaction(|c| -> Result<_>)):
No savepoints
DuckDB supports only
BEGIN / COMMIT / ROLLBACK / ABORT — not SAVEPOINT / RELEASE
/ ROLLBACK TO. There is deliberately no savepoint API.See also
- Executing SQL — the statements you group in a transaction.
- Async · Pooling — running transactions off the executor.
- Helper macros —
transaction!.