面试题答案
一键面试设计思路
- 连接池设计:使用连接池来管理数据库连接,实现连接的高效复用。连接池可以使用队列或其他合适的数据结构来存储可用连接。
- RAII机制:利用C++的RAII(Resource Acquisition Is Initialization)机制,在对象构造时获取数据库连接,在对象析构时释放连接回连接池。这样可以确保连接在使用完毕后正确释放,避免资源泄漏。
- 异常处理:在获取连接、执行数据库操作以及释放连接的过程中,要处理各种数据库异常。可以通过try - catch块捕获异常,并进行适当的处理,如记录日志、重试操作等。
- 智能指针与自定义资源释放策略:使用智能指针(如
std::unique_ptr
或std::shared_ptr
)来管理数据库连接对象,同时自定义资源释放策略,确保连接正确释放回连接池。
优化点
- 连接池大小优化:根据应用的实际负载和数据库服务器的性能,合理调整连接池的大小,避免连接过多或过少导致的性能问题。
- 异步操作:对于一些耗时的数据库操作,可以考虑使用异步操作来提高并发性能,避免线程阻塞。
- 连接健康检查:定期检查连接池中的连接是否有效,对于无效连接及时进行重连或移除。
代码实现
#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机制和智能指针来管理数据库连接,同时处理了可能出现的数据库异常。在实际应用中,还需要根据具体需求进一步优化和完善,如增加日志记录、连接健康检查等功能。