zdbpp.h File Reference

Detailed Description

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

  1. Create ConnectionPool instances at application startup.
  2. Maintain these instances for the entire duration of your application's runtime.
  3. Use a single ConnectionPool for each distinct database you need to connect to.
  4. Consider wrapping ConnectionPool instances in a singleton or dependency injection pattern for easy access across your application.
  5. 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, []() {
// Configure and start main pool
ConnectionPool& main = getMainPool();
main.setInitialConnections(5); // Example value
main.setMaxConnections(20); // Example value
main.setConnectionTimeout(30); // 30 seconds timeout
main.start();
// Configure and start analytics pool
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();
// Use default isolation level
con.beginTransaction();
con.execute("UPDATE accounts SET balance = balance - ? WHERE id = ?", 100.0, 1);
con.commit();
// Alternatively, specify the transaction's isolation level
con.beginTransaction(TRANSACTION_SERIALIZABLE));
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;
// Connection is automatically returned to pool when it goes out of scope
// If an exception occurred before commit, it will automatically rollback
} catch (const sql_exception& e) {
std::cerr << "Transfer failed: " << e.what() << std::endl;
}

Key points about exception handling in this library:

  1. All database operations that can fail will throw sql_exception.
  2. sql_exception provides informative error messages through its what() method.
  3. You should wrap database operations in try-catch blocks to handle potential errors gracefully.
  4. 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.

Data Structures

class  sql_exception
 Exception class for SQL related errors. More...
 
class  URL
 Represents an immutable Uniform Resource Locator. More...
 
class  ResultSet
 Represents a database result set. More...
 
class  PreparedStatement
 Represents a pre-compiled SQL statement for later execution. More...
 
class  Connection
 Represents a connection to a SQL database system. More...
 
class  ConnectionPool
 Represents a database connection pool. More...
 

Namespaces

namespace  zdb
 
namespace  zdb::version
 

Functions

constexpr bool is_compatible_with (int required_major, int required_minor, int required_revision=0)
 

Variables

constexpr int major = LIBZDB_MAJOR
 
constexpr int minor = LIBZDB_MINOR
 
constexpr int revision = LIBZDB_REVISION
 
constexpr int number = LIBZDB_VERSION_NUMBER
 
constexpr std::string_view string = LIBZDB_VERSION
 

Copyright © Tildeslash Ltd. All rights reserved.