BEGIN, COMMIT и ROLLBACK через sqlite3_exec складывают шаги в одну транзакцию до явной фиксации.">
Следите за новинками
в нашем Telegram канале. Жми, чтобы подписаться:)
⊗cpSpDbTrn 614 of 696 menu
◀ ▶

Транзакция SQLite в C++

По умолчанию SQLite фиксирует каждый запрос отдельно.

Команды BEGIN, COMMIT и ROLLBACK через sqlite3_exec складывают шаги в одну транзакцию до явной фиксации или отката. Два успешных INSERT попадут на диск только после COMMIT:

#include <iostream> #include <sqlite3.h> int main() { sqlite3* db = nullptr; if (sqlite3_open("txn_ok.db", &db) != SQLITE_OK) { std::cerr << sqlite3_errmsg(db) << "\n"; sqlite3_close(db); return 1; } char* err = nullptr; if (sqlite3_exec( db, "CREATE TABLE IF NOT EXISTS moves (" "id INTEGER PRIMARY KEY," "step TEXT NOT NULL" ")", nullptr, nullptr, &err ) != SQLITE_OK) { std::cerr << err << "\n"; sqlite3_free(err); sqlite3_close(db); return 1; } if (sqlite3_exec(db, "BEGIN", nullptr, nullptr, &err) != SQLITE_OK) { std::cerr << err << "\n"; sqlite3_free(err); sqlite3_close(db); return 1; } sqlite3_stmt* first = nullptr; if (sqlite3_prepare_v2( db, "INSERT INTO moves (step) VALUES (?)", -1, &first, nullptr ) != SQLITE_OK) { std::cerr << sqlite3_errmsg(db) << "\n"; sqlite3_close(db); return 1; } sqlite3_bind_text(first, 1, "load", -1, SQLITE_STATIC); sqlite3_step(first); sqlite3_finalize(first); sqlite3_stmt* second = nullptr; if (sqlite3_prepare_v2( db, "INSERT INTO moves (step) VALUES (?)", -1, &second, nullptr ) != SQLITE_OK) { std::cerr << sqlite3_errmsg(db) << "\n"; sqlite3_close(db); return 1; } sqlite3_bind_text(second, 1, "seal", -1, SQLITE_STATIC); sqlite3_step(second); sqlite3_finalize(second); if (sqlite3_exec(db, "COMMIT", nullptr, nullptr, &err) != SQLITE_OK) { std::cerr << err << "\n"; sqlite3_free(err); sqlite3_close(db); return 1; } sqlite3_close(db); return 0; }

При ошибке между шагами ROLLBACK отменяет несохраненные изменения в рамках транзакции:

#include <iostream> #include <sqlite3.h> int main() { sqlite3* db = nullptr; if (sqlite3_open("txn_fail.db", &db) != SQLITE_OK) { std::cerr << sqlite3_errmsg(db) << "\n"; sqlite3_close(db); return 1; } char* err = nullptr; if (sqlite3_exec( db, "CREATE TABLE IF NOT EXISTS moves (" "id INTEGER PRIMARY KEY," "step TEXT NOT NULL" ")", nullptr, nullptr, &err ) != SQLITE_OK) { std::cerr << err << "\n"; sqlite3_free(err); sqlite3_close(db); return 1; } if (sqlite3_exec(db, "BEGIN", nullptr, nullptr, &err) != SQLITE_OK) { std::cerr << err << "\n"; sqlite3_free(err); sqlite3_close(db); return 1; } sqlite3_stmt* insert = nullptr; if (sqlite3_prepare_v2( db, "INSERT INTO moves (step) VALUES (?)", -1, &insert, nullptr ) != SQLITE_OK) { std::cerr << sqlite3_errmsg(db) << "\n"; sqlite3_close(db); return 1; } sqlite3_bind_text(insert, 1, "start", -1, SQLITE_STATIC); sqlite3_step(insert); sqlite3_finalize(insert); sqlite3_exec(db, "ROLLBACK", nullptr, nullptr, &err); sqlite3_stmt* count = nullptr; if (sqlite3_prepare_v2( db, "SELECT COUNT(*) FROM moves", -1, &count, nullptr ) != SQLITE_OK) { std::cerr << sqlite3_errmsg(db) << "\n"; sqlite3_close(db); return 1; } if (sqlite3_step(count) == SQLITE_ROW) { std::cout << sqlite3_column_int(count, 0) << "\n"; } sqlite3_finalize(count); sqlite3_close(db); return 0; }

Создайте таблицу ledger_tx в bank.db с полем note, выполните два добавления в одной транзакции и зафиксируйте их.

Повторите два добавления, но вызовите откат перед фиксацией и выведите 0 строк в таблице.

← →
↑
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить