MST
星途 面试题库

面试题:C++ RAII与数据库连接性能优化及异常处理

在高并发的数据库应用场景中,使用C++ RAII管理数据库连接。不仅要保证连接的高效复用,还要处理各种复杂的数据库异常(如连接超时、数据库锁冲突等)。请详细阐述你的设计思路,并给出优化点以及对应的代码实现,包括如何使用智能指针、自定义资源释放策略等相关C++技术。
43.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 连接池设计:使用连接池来管理数据库连接,实现连接的高效复用。连接池可以使用队列或其他合适的数据结构来存储可用连接。
  2. RAII机制:利用C++的RAII(Resource Acquisition Is Initialization)机制,在对象构造时获取数据库连接,在对象析构时释放连接回连接池。这样可以确保连接在使用完毕后正确释放,避免资源泄漏。
  3. 异常处理:在获取连接、执行数据库操作以及释放连接的过程中,要处理各种数据库异常。可以通过try - catch块捕获异常,并进行适当的处理,如记录日志、重试操作等。
  4. 智能指针与自定义资源释放策略:使用智能指针(如std::unique_ptrstd::shared_ptr)来管理数据库连接对象,同时自定义资源释放策略,确保连接正确释放回连接池。

优化点

  1. 连接池大小优化:根据应用的实际负载和数据库服务器的性能,合理调整连接池的大小,避免连接过多或过少导致的性能问题。
  2. 异步操作:对于一些耗时的数据库操作,可以考虑使用异步操作来提高并发性能,避免线程阻塞。
  3. 连接健康检查:定期检查连接池中的连接是否有效,对于无效连接及时进行重连或移除。

代码实现

#include <iostream>
#include <memory>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <chrono>
#include <mysql/mysql.h>

// 数据库连接配置
const char* host = "localhost";
const char* user = "root";
const char* pass = "password";
const char* db = "test";
unsigned int port = 3306;

// 连接池类
class ConnectionPool {
public:
    ConnectionPool(int poolSize) : poolSize(poolSize) {
        for (int i = 0; i < poolSize; ++i) {
            MYSQL* conn = mysql_init(nullptr);
            if (conn && mysql_real_connect(conn, host, user, pass, db, port, nullptr, 0)) {
                connections.push(conn);
            } else {
                std::cerr << "Failed to connect to database: " << mysql_error(conn) << std::endl;
                if (conn) mysql_close(conn);
            }
        }
    }

    ~ConnectionPool() {
        while (!connections.empty()) {
            MYSQL* conn = connections.front();
            connections.pop();
            mysql_close(conn);
        }
    }

    MYSQL* getConnection() {
        std::unique_lock<std::mutex> lock(mutex_);
        while (connections.empty()) {
            cv.wait(lock);
        }
        MYSQL* conn = connections.front();
        connections.pop();
        return conn;
    }

    void releaseConnection(MYSQL* conn) {
        std::unique_lock<std::mutex> lock(mutex_);
        connections.push(conn);
        cv.notify_one();
    }

private:
    std::queue<MYSQL*> connections;
    std::mutex mutex_;
    std::condition_variable cv;
    int poolSize;
};

// 数据库连接RAII封装类
class DatabaseConnection {
public:
    DatabaseConnection(ConnectionPool& pool) : pool(pool) {
        connection = pool.getConnection();
    }

    ~DatabaseConnection() {
        if (connection) {
            pool.releaseConnection(connection);
        }
    }

    MYSQL* operator->() {
        return connection;
    }

    MYSQL& operator*() {
        return *connection;
    }

private:
    MYSQL* connection;
    ConnectionPool& pool;
};

// 自定义资源释放策略
struct ConnectionDeleter {
    ConnectionPool& pool;
    ConnectionDeleter(ConnectionPool& p) : pool(p) {}
    void operator()(MYSQL* conn) {
        if (conn) {
            pool.releaseConnection(conn);
        }
    }
};

// 使用智能指针管理数据库连接
using ConnectionPtr = std::unique_ptr<MYSQL, ConnectionDeleter>;

// 示例函数,使用数据库连接
void executeQuery(ConnectionPool& pool) {
    // 使用RAII封装类
    DatabaseConnection conn(pool);
    if (mysql_query(conn, "SELECT * FROM your_table")) {
        std::cerr << "Query failed: " << mysql_error(conn) << std::endl;
    } else {
        MYSQL_RES* result = mysql_store_result(conn);
        if (result) {
            while (MYSQL_ROW row = mysql_fetch_row(result)) {
                // 处理结果
                for (int i = 0; i < mysql_num_fields(result); ++i) {
                    std::cout << row[i] << "\t";
                }
                std::cout << std::endl;
            }
            mysql_free_result(result);
        } else {
            std::cerr << "Failed to store result: " << mysql_error(conn) << std::endl;
        }
    }

    // 使用智能指针
    ConnectionPtr ptr(pool.getConnection(), ConnectionDeleter(pool));
    if (mysql_query(ptr.get(), "SELECT * FROM your_table")) {
        std::cerr << "Query failed: " << mysql_error(ptr.get()) << std::endl;
    } else {
        MYSQL_RES* result = mysql_store_result(ptr.get());
        if (result) {
            while (MYSQL_ROW row = mysql_fetch_row(result)) {
                // 处理结果
                for (int i = 0; i < mysql_num_fields(result); ++i) {
                    std::cout << row[i] << "\t";
                }
                std::cout << std::endl;
            }
            mysql_free_result(result);
        } else {
            std::cerr << "Failed to store result: " << mysql_error(ptr.get()) << std::endl;
        }
    }
}

使用示例

int main() {
    ConnectionPool pool(10);
    std::thread t1(executeQuery, std::ref(pool));
    std::thread t2(executeQuery, std::ref(pool));

    t1.join();
    t2.join();

    return 0;
}

以上代码实现了一个简单的数据库连接池,并使用RAII机制和智能指针来管理数据库连接,同时处理了可能出现的数据库异常。在实际应用中,还需要根据具体需求进一步优化和完善,如增加日志记录、连接健康检查等功能。