Ответ
В C++ приложениях для работы с SQL-транзакциями используются библиотеки-коннекторы (например, libpqxx для PostgreSQL, MySQL Connector/C++, SQLite C/C++ Interface или абстракции вроде ODBC, Qt SQL). Общий паттерн работы с транзакцией следующий:
- Начало транзакции: Явный вызов
BEGINилиSTART TRANSACTION. Многие библиотеки предоставляют объектTransaction, конструктор которого автоматически начинает транзакцию. - Выполнение операций: Выполнение одного или нескольких SQL-запросов (
INSERT,UPDATE,DELETE,SELECT) в рамках этой транзакции. - Фиксация или откат: Если все операции успешны — выполняется
COMMIT, изменения сохраняются в БД. Если произошла ошибка — выполняетсяROLLBACK, все изменения в рамках транзакции отменяются.
Пример с использованием библиотеки SQLite (C API):
#include <sqlite3.h>
#include <iostream>
int main() {
sqlite3* db;
char* errMsg = nullptr;
sqlite3_open(":memory:", &db); // Открываем БД в памяти.
// 1. Явно начинаем транзакцию.
sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, &errMsg);
// 2. Выполняем операции.
bool success = true;
if (sqlite3_exec(db, "CREATE TABLE test(id INT);", nullptr, nullptr, &errMsg) != SQLITE_OK) {
success = false;
}
if (success && sqlite3_exec(db, "INSERT INTO test VALUES (1);", nullptr, nullptr, &errMsg) != SQLITE_OK) {
success = false;
}
// 3. Фиксация или откат.
if (success) {
sqlite3_exec(db, "COMMIT;", nullptr, nullptr, &errMsg);
std::cout << "Transaction committed.n";
} else {
std::cerr << "Error: " << errMsg << " -> Rolling back.n";
sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
sqlite3_free(errMsg);
}
sqlite3_close(db);
return 0;
}
Пример с использованием более современной обёртки (SQLiteCpp):
#include <SQLiteCpp/SQLiteCpp.h>
#include <iostream>
try {
SQLite::Database db(":memory:", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);
// Объект Transaction автоматически выполняет BEGIN в конструкторе.
SQLite::Transaction transaction(db);
db.exec("CREATE TABLE test (id INTEGER)");
db.exec("INSERT INTO test VALUES (42)");
// commit() автоматически вызывается в деструкторе, если не вызван rollback().
transaction.commit();
std::cout << "Transaction committed successfully.n";
} catch (const std::exception& e) {
// При выбросе исключения transaction будет уничтожен, и произойдёт автоматический rollback.
std::cerr << "SQLite error: " << e.what() << std::endl;
}
Ключевые моменты:
- Режим автокоммита обычно включён по умолчанию. При явном начале транзакции он отключается.
- Долгие транзакции могут удерживать блокировки и негативно влиять на параллельную работу.
- Уровни изоляции транзакций (Read Committed, Repeatable Read и др.) позволяют управлять видимостью изменений между параллельными транзакциями и настраиваются через SQL-команды (например,
SET TRANSACTION ISOLATION LEVEL ...).