Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
transaction_management.cpp File Reference

Demonstrates transaction management with commit and rollback. More...

#include <iostream>
#include <memory>
#include <string>
#include <variant>
#include "database/database_manager.h"
#include "database/core/database_context.h"
Include dependency graph for transaction_management.cpp:

Go to the source code of this file.

Classes

class  transaction_guard
 RAII transaction guard that rolls back on destruction unless committed. More...
 

Functions

int main ()
 

Detailed Description

Demonstrates transaction management with commit and rollback.

This example shows how to:

  • Begin, commit, and rollback transactions
  • Use the in_transaction() check
  • Handle errors within a transaction scope
  • Implement a simple RAII-style transaction guard pattern

Prerequisites:

  • A running PostgreSQL server
  • Update the connection string below with valid credentials

Definition in file transaction_management.cpp.

Function Documentation

◆ main()

int main ( )

Definition at line 80 of file transaction_management.cpp.

81{
82 std::cout << "=== transaction_management example ===" << std::endl;
83
84 // Setup
85 auto context = std::make_shared<database_context>();
86 auto db_manager = std::make_shared<database_manager>(context);
87 db_manager->set_mode(database_types::postgres);
88
89 std::string connection_string
90 = "host=localhost port=5432 dbname=example_db user=user password=password";
91
92 auto connect_result = db_manager->connect_result(connection_string);
93 if (!connect_result.is_ok())
94 {
95 std::cerr << "Connection failed. Ensure PostgreSQL is running." << std::endl;
96 return 1;
97 }
98 std::cout << "Connected" << std::endl;
99
100 // Prepare a test table
101 db_manager->create_query_result(R"(
102 CREATE TABLE IF NOT EXISTS accounts (
103 id SERIAL PRIMARY KEY,
104 name VARCHAR(100) NOT NULL,
105 balance DECIMAL(12,2) NOT NULL DEFAULT 0.00
106 )
107 )");
108 db_manager->execute_query_result("DELETE FROM accounts");
109 db_manager->execute_query_result(
110 "INSERT INTO accounts (name, balance) VALUES ('Alice', 1000.00)");
111 db_manager->execute_query_result(
112 "INSERT INTO accounts (name, balance) VALUES ('Bob', 500.00)");
113
114 // -------------------------------------------------------
115 // Scenario 1: Successful transaction (transfer funds)
116 // -------------------------------------------------------
117 std::cout << "\n--- Scenario 1: Successful transfer ---" << std::endl;
118 {
119 auto begin_result = db_manager->begin_transaction();
120 if (!begin_result.is_ok())
121 {
122 std::cerr << "Failed to begin transaction" << std::endl;
123 return 1;
124 }
125 std::cout << "Transaction started, in_transaction = "
126 << std::boolalpha << db_manager->in_transaction() << std::endl;
127
128 // Transfer 200 from Alice to Bob
129 db_manager->execute_query_result(
130 "UPDATE accounts SET balance = balance - 200 WHERE name = 'Alice'");
131 db_manager->execute_query_result(
132 "UPDATE accounts SET balance = balance + 200 WHERE name = 'Bob'");
133
134 auto commit_result = db_manager->commit_transaction();
135 if (commit_result.is_ok())
136 {
137 std::cout << "Transaction committed" << std::endl;
138 }
139
140 // Verify balances
141 auto result = db_manager->select_query_result(
142 "SELECT name, balance FROM accounts ORDER BY name");
143 if (result.is_ok())
144 {
145 for (const auto& row : result.value())
146 {
147 for (const auto& [col, val] : row)
148 {
149 std::cout << " " << col << " = ";
150 std::visit([](const auto& v) { std::cout << v; }, val);
151 std::cout << " ";
152 }
153 std::cout << std::endl;
154 }
155 }
156 }
157
158 // -------------------------------------------------------
159 // Scenario 2: Rollback on error
160 // -------------------------------------------------------
161 std::cout << "\n--- Scenario 2: Rollback on error ---" << std::endl;
162 {
163 auto begin_result = db_manager->begin_transaction();
164 if (!begin_result.is_ok())
165 {
166 std::cerr << "Failed to begin transaction" << std::endl;
167 return 1;
168 }
169
170 // Debit Alice
171 db_manager->execute_query_result(
172 "UPDATE accounts SET balance = balance - 5000 WHERE name = 'Alice'");
173
174 // Simulate a business rule check: Alice would go negative
175 auto check = db_manager->select_query_result(
176 "SELECT balance FROM accounts WHERE name = 'Alice'");
177
178 bool should_rollback = false;
179 if (check.is_ok() && !check.value().empty())
180 {
181 const auto& balance_val = check.value()[0].at("balance");
182 // Check if balance went negative (as a string comparison for simplicity)
183 std::visit(
184 [&should_rollback](const auto& v)
185 {
186 using T = std::decay_t<decltype(v)>;
187 if constexpr (std::is_same_v<T, double>)
188 {
189 should_rollback = (v < 0.0);
190 }
191 else if constexpr (std::is_same_v<T, std::string>)
192 {
193 // Some backends return numeric values as strings
194 should_rollback = (!v.empty() && v[0] == '-');
195 }
196 },
197 balance_val);
198 }
199
200 if (should_rollback)
201 {
202 std::cout << "Business rule violation detected, rolling back" << std::endl;
203 db_manager->rollback_transaction();
204 std::cout << "Transaction rolled back, in_transaction = "
205 << std::boolalpha << db_manager->in_transaction() << std::endl;
206 }
207 else
208 {
209 db_manager->commit_transaction();
210 std::cout << "Transaction committed (balance was not negative)" << std::endl;
211 }
212
213 // Verify balances unchanged
214 auto result = db_manager->select_query_result(
215 "SELECT name, balance FROM accounts ORDER BY name");
216 if (result.is_ok())
217 {
218 std::cout << "Balances after rollback:" << std::endl;
219 for (const auto& row : result.value())
220 {
221 for (const auto& [col, val] : row)
222 {
223 std::cout << " " << col << " = ";
224 std::visit([](const auto& v) { std::cout << v; }, val);
225 std::cout << " ";
226 }
227 std::cout << std::endl;
228 }
229 }
230 }
231
232 // -------------------------------------------------------
233 // Scenario 3: RAII transaction guard
234 // -------------------------------------------------------
235 std::cout << "\n--- Scenario 3: RAII transaction guard ---" << std::endl;
236 {
237 try
238 {
239 transaction_guard guard(db_manager);
240 std::cout << "Guard started transaction" << std::endl;
241
242 db_manager->execute_query_result(
243 "INSERT INTO accounts (name, balance) VALUES ('Carol', 750.00)");
244
245 // Commit explicitly through the guard
246 guard.commit();
247 std::cout << "Guard committed transaction" << std::endl;
248 }
249 catch (const std::exception& e)
250 {
251 std::cerr << "Transaction error: " << e.what() << std::endl;
252 }
253
254 // Verify Carol was added
255 auto result = db_manager->select_query_result(
256 "SELECT name, balance FROM accounts ORDER BY name");
257 if (result.is_ok())
258 {
259 std::cout << "Accounts after guard commit:" << std::endl;
260 for (const auto& row : result.value())
261 {
262 for (const auto& [col, val] : row)
263 {
264 std::cout << " " << col << " = ";
265 std::visit([](const auto& v) { std::cout << v; }, val);
266 std::cout << " ";
267 }
268 std::cout << std::endl;
269 }
270 }
271 }
272
273 // Cleanup
274 db_manager->disconnect_result();
275 std::cout << "\nDisconnected" << std::endl;
276
277 std::cout << "=== transaction_management example completed ===" << std::endl;
278 return 0;
279}
RAII transaction guard that rolls back on destruction unless committed.

References transaction_guard::commit().

Here is the call graph for this function: