MST

星途 面试题库

面试题:C++ RAII在复杂数据库操作场景下的应用

在一个多线程环境下,使用C++ RAII管理数据库连接,要考虑连接池的复用。请设计一个类结构来实现这一功能,并且说明如何处理线程安全问题,给出关键代码片段及详细解释。
39.0万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

类结构设计

  1. 数据库连接类 DBConnection:表示一个数据库连接,封装实际的数据库连接操作。
  2. 连接池类 DBConnectionPool:管理数据库连接池,负责创建、分配和回收连接。
  3. RAII 包装类 DBConnectionRAII:通过 RAII 机制在对象生命周期内管理数据库连接的获取和释放,确保连接的正确使用和回收。

线程安全处理

  1. 使用互斥锁(std::mutex)来保护连接池的共享资源,如连接的获取和释放操作。
  2. 对于线程安全的队列(用于存储连接),可以使用 std::queue 并结合互斥锁和条件变量(std::condition_variable)来实现线程安全的入队和出队操作。

关键代码片段及解释

DBConnection

class DBConnection {
public:
    // 构造函数,初始化数据库连接
    DBConnection() {
        // 实际连接数据库的代码,例如使用数据库驱动 API
        // 这里省略具体实现
    }

    // 析构函数,关闭数据库连接
    ~DBConnection() {
        // 关闭数据库连接的代码,例如使用数据库驱动 API
        // 这里省略具体实现
    }

    // 执行 SQL 查询的方法
    void executeQuery(const std::string& query) {
        // 执行 SQL 查询的代码,例如使用数据库驱动 API
        // 这里省略具体实现
    }
};

解释:DBConnection 类封装了数据库连接的基本操作,包括连接的创建、关闭以及执行 SQL 查询。

DBConnectionPool

class DBConnectionPool {
public:
    // 单例模式获取连接池实例
    static DBConnectionPool& getInstance() {
        static DBConnectionPool instance;
        return instance;
    }

    // 获取一个数据库连接
    std::shared_ptr<DBConnection> getConnection() {
        std::unique_lock<std::mutex> lock(mutex_);
        while (connections_.empty()) {
            // 如果连接池为空,等待有连接被释放
            condition_.wait(lock);
        }
        std::shared_ptr<DBConnection> connection = connections_.front();
        connections_.pop();
        return connection;
    }

    // 释放一个数据库连接回连接池
    void releaseConnection(std::shared_ptr<DBConnection> connection) {
        std::unique_lock<std::mutex> lock(mutex_);
        connections_.push(connection);
        condition_.notify_one();
    }

private:
    // 连接池构造函数,初始化连接池
    DBConnectionPool() {
        // 初始化连接池中的连接数量,例如 10 个
        for (int i = 0; i < 10; ++i) {
            connections_.push(std::make_shared<DBConnection>());
        }
    }

    // 禁止拷贝构造和赋值运算符
    DBConnectionPool(const DBConnectionPool&) = delete;
    DBConnectionPool& operator=(const DBConnectionPool&) = delete;

    std::queue<std::shared_ptr<DBConnection>> connections_;
    std::mutex mutex_;
    std::condition_variable condition_;
};

解释:DBConnectionPool 类采用单例模式,确保整个应用程序只有一个连接池实例。getConnection 方法从连接池中获取一个连接,如果连接池为空则等待。releaseConnection 方法将连接释放回连接池,并通知等待的线程。

DBConnectionRAII

class DBConnectionRAII {
public:
    // 构造函数获取数据库连接
    DBConnectionRAII() : connection_(DBConnectionPool::getInstance().getConnection()) {}

    // 析构函数释放数据库连接
    ~DBConnectionRAII() {
        if (connection_) {
            DBConnectionPool::getInstance().releaseConnection(connection_);
        }
    }

    // 执行 SQL 查询的方法,通过 RAII 包装类调用实际连接的方法
    void executeQuery(const std::string& query) {
        if (connection_) {
            connection_->executeQuery(query);
        }
    }

private:
    std::shared_ptr<DBConnection> connection_;
};

解释:DBConnectionRAII 类通过 RAII 机制在对象构造时获取数据库连接,在对象析构时释放连接。这样可以确保连接在使用完毕后正确地返回连接池,避免资源泄漏。同时,该类还提供了执行 SQL 查询的接口,通过实际的 DBConnection 对象来执行查询。