Skip to content

Transactions

Transactions ensure atomicity across multiple database operations. All queries within a transaction either commit together or roll back together.


begin_transaction(pool, cb) — Starting a Transaction

Gets a connection from the pool and begins a MySQL transaction. The callback receives the transaction object (shared_ptr<transaction>).

cpp
auto* pool = db.get_pool("primary");

pool->begin_transaction([](auto ec, auto tx) {
    if (ec) {
        fmt::println("Failed to start transaction: {}", ec.what());
        return;
    }

    // Run queries within the transaction
    tx->run([](auto ec, auto results) {
        if (ec) return;
        // Process results
    }, "INSERT INTO users (name) VALUES (?)", {"Alice"});
});
ParamTypeDescription
cbcallbackReceives (error_code, shared_ptr<transaction>). The transaction is only valid within this callback.

tx->run(cb, query, params) — Running Queries Inside a Transaction

Executes a query within the transaction context. Uses the same connection until commit or rollback.

run(cb, query) — Simple query:

cpp
tx->run([](auto ec, auto results) {
    if (ec) { /* handle */ }
}, "SELECT * FROM users WHERE id = 1");

run(cb, query, params) — Parameterized query:

cpp
tx->run([](auto ec, auto results) {
    if (ec) return;
}, "UPDATE accounts SET balance = balance - ?", {100});

tx->commit(cb) — Committing

Persists all changes made during the transaction.

cpp
tx->commit([](auto ec) {
    if (!ec) fmt::println("Transaction committed!");
});

tx->rollback(cb) — Rolling Back

Undoes all changes made during the transaction.

cpp
tx->rollback([](auto ec) {
    fmt::println("Transaction rolled back");
});

Chaining Multiple Queries

Chain queries sequentially, rolling back on any failure:

cpp
pool->begin_transaction([](auto ec, auto tx) {
    if (ec) return;

    tx->run([tx](auto ec, auto results) {
        if (ec) return tx->rollback([](auto){});

        tx->run([tx](auto ec, auto r2) {
            if (ec) return tx->rollback([](auto){});
            tx->commit([](auto ec) { });
        }, "UPDATE accounts SET balance = balance - ?", {100});
    }, "INSERT INTO transfers (amount) VALUES (?)", {100});
});

Important: Capture tx by value in nested lambdas ([tx]), not by reference ([&tx]). The transaction may outlive the current scope — a reference capture will become a dangling pointer when the outer callback returns.


Checking Transaction State

cpp
bool finished = tx->is_finished();  // true after commit or rollback