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:1794
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.