zdbpp.h - C++ Interface for libzdb
A modern, type-safe way to interact with various SQL databases from C++ applications.
Features
- Thread-safe Database Connection Pool
- Connect to multiple database systems simultaneously
- Zero runtime configuration, connect using a URL scheme
- Supports MySQL, PostgreSQL, SQLite, and Oracle
- Modern C++ features (C++20 or later required)
Core Concepts
The central class in this library is ConnectionPool
, which manages database connections. All other main classes (Connection
, PreparedStatement
, and ResultSet
) are obtained through the ConnectionPool
or its derivatives.
ConnectionPool and URL
The ConnectionPool
is initialized with a URL
object, which specifies the database connection details:
zdb::URL url(
"mysql://localhost:3306/mydb?user=root&password=secret");
pool.start();
Represents a database connection pool.
Definition zdbpp.h:1769
Represents an immutable Uniform Resource Locator.
Definition zdbpp.h:331
A ConnectionPool is designed to be a long-lived object that manages database connections throughout the lifetime of your application. Typically, you would instantiate one or more ConnectionPool objects as part of a resource management class or in the global scope of your application.
Best Practices for Using ConnectionPool
- Create ConnectionPool instances at application startup.
- Maintain these instances for the entire duration of your application's runtime.
- Use a single ConnectionPool for each distinct database you need to connect to.
- Consider wrapping ConnectionPool instances in a singleton or dependency injection pattern for easy access across your application.
- Ensure proper shutdown of ConnectionPool instances when your application terminates to release all database resources cleanly.
Example of a global ConnectionPool manager:
class DatabaseManager {
public:
static ConnectionPool& getMainPool() {
static ConnectionPool mainPool("mysql://localhost/maindb?user=root&password=pass");
return mainPool;
}
static ConnectionPool& getAnalyticsPool() {
static ConnectionPool analyticsPool("postgresql://analyst:pass@192.168.8.217/datawarehouse");
return analyticsPool;
}
static void initialize() {
static std::once_flag initFlag;
std::call_once(initFlag, []() {
ConnectionPool& main = getMainPool();
main.setInitialConnections(5);
main.setMaxConnections(20);
main.setConnectionTimeout(30);
main.start();
ConnectionPool& analytics = getAnalyticsPool();
analytics.setInitialConnections(2);
analytics.setMaxConnections(10);
analytics.start();
});
}
static void shutdown() {
getMainPool().stop();
getAnalyticsPool().stop();
}
};
Usage Examples
Basic Query Execution
auto& pool = DatabaseManager::getMainPool();
auto con = pool.getConnection();
ResultSet result = con.executeQuery("SELECT name, age FROM users WHERE id = ?", 1);
if (result.next()) {
std::cout << "Name: " << result.getString("name").value_or("N/A")
<< ", Age: " << result.getInt("age") << std::endl;
}
Using PreparedStatement
auto& pool = DatabaseManager::getAnalyticsPool();
auto con = pool.getConnection();
auto stmt = con.prepareStatement("INSERT INTO logs (message, timestamp) VALUES (?, ?)");
stmt.bindValues("User logged in", std::time(nullptr));
stmt.execute();
Transaction Example
Connection con = pool.getConnection();
con.beginTransaction();
con.execute("UPDATE accounts SET balance = balance - ? WHERE id = ?", 100.0, 1);
con.commit();
con.execute("UPDATE accounts SET balance = balance + ? WHERE id = ?", 100.0, 2);
con.commit();
@ TRANSACTION_SERIALIZABLE
Highest isolation level.
Definition Connection.h:181
Exception Handling
All database-related errors are thrown as sql_exception
, which derives from std::runtime_error
.
Example of Exception Handling
try {
Connection con = pool.getConnection();
con.beginTransaction();
con.execute("UPDATE accounts SET balance = balance - ? WHERE id = ?", 100.0, 1);
con.execute("UPDATE accounts SET balance = balance + ? WHERE id = ?", 100.0, 2);
con.commit();
std::cout << "Transfer successful" << std::endl;
} catch (const sql_exception& e) {
std::cerr << "Transfer failed: " << e.what() << std::endl;
}
Key points about exception handling in this library:
- All database operations that can fail will throw
sql_exception
.
sql_exception
provides informative error messages through its what()
method.
- You should wrap database operations in try-catch blocks to handle potential errors gracefully.
- The library ensures that resources are properly managed even when exceptions are thrown, preventing resource leaks.
- Note
- For detailed API documentation, refer to the comments for each class in this header file. Visit libzdb's homepage for additional documentation and examples.