DBConnector 函数手册
C++ 后端服务器框架DBConnector 函数手册
CHAPTER 17

DBConnector 函数手册

5 分钟阅读 · 1,282 字

依据源码:include/DBConnector.h、src/DBConnector.cpp。


0. 全局静态成员与总体职责

静态成员

  • DBConnector* DBConnector::instance_ = nullptr;
  • std::mutex DBConnector::mutex_;

模块职责

  • 管理 MySQL 连接句柄 MYSQL* db_
  • 提供查询与执行接口
  • 提供单例初始化/获取/销毁
  • 提供最后错误信息 last_error_
  • 提供 SQL 字面量转义 escapeSqlLiteral

1. 构造与析构

1.1 DBConnector::DBConnector(std::string host, std::string user, std::string passwd, std::string dbname, unsigned int port = 3306)(私有)

  • 位置:src/DBConnector.cpp
  • 作用:保存连接参数并初始化 MySQL 句柄。

执行步骤

  1. 成员初始化:
    • db_ = nullptr
    • host_/user_/passwd_/dbname_/port_ 通过 std::move 接管
  2. db_ = mysql_init(nullptr)
  3. 若 db_ == nullptr:
    • last_error_ = "MySQL句柄初始化失败"
    • 抛 std::runtime_error(last_error_)

关键点

  • 构造阶段只初始化句柄,不建立 TCP 连接。
  • 单例未初始化前不能外部直接构造(构造函数私有)。

1.2 DBConnector::~DBConnector()

  • 位置:src/DBConnector.cpp
  • 作用:关闭连接句柄并清理错误状态。

执行步骤

  1. if (db_ != nullptr) mysql_close(db_);
  2. db_ = nullptr
  3. last_error_.clear()

2. 内部工具函数

2.1 static void DBConnector::freeResult(MYSQL_RES* res)(私有)

  • 位置:src/DBConnector.cpp
  • 作用:安全释放结果集。

逻辑

  • if (res != nullptr) mysql_free_result(res);

3. 连接与执行接口

3.1 bool DBConnector::connect()

  • 作用:根据构造保存的参数建立 MySQL 连接。

执行步骤

  1. 若 db_ == nullptr:
    • last_error_ = "MySQL句柄未初始化"
    • 返回 false
  2. mysql_options(db_, MYSQL_SET_CHARSET_NAME, "utf8mb4")
  3. 调用 mysql_real_connect(...)
  4. 若失败:
    • last_error_ = "连接失败: " + mysql_error(db_)
    • 返回 false
  5. 成功:
    • last_error_.clear()
    • 返回 true

面试点

  • 这里的 connect 可重复调用,但未显式处理“已连接再连接”的状态迁移。
  • 字符集固定 utf8mb4,这是正确默认选择。

3.2 std::vector<std::map<std::string, std::string>> DBConnector::query(const std::string& sql)

  • 作用:执行 SELECT 类查询并返回二维字符串映射结果。

返回结构

  • 外层 vector:每一行
  • 内层 map:字段名 -> 字符串值

执行步骤

  1. result 初始化为空。
  2. 若 db_ == nullptr:
    • last_error_ = "未连接数据库"
    • 返回空 result
  3. mysql_query(db_, sql.c_str())
    • 失败:last_error_ = "SQL执行失败: " + mysql_error(db_),返回空
  4. MYSQL_RES* res = mysql_store_result(db_)
    • 若 nullptr:last_error_ = "获取结果集失败: " + mysql_error(db_),返回空
  5. 获取字段元信息:
    • int field_count = mysql_num_fields(res);
    • MYSQL_FIELD* fields = mysql_fetch_fields(res);
    • 若 fields == nullptr || field_count <= 0:
      • freeResult(res)
      • last_error_ = "无字段信息"
      • 返回空
  6. 行遍历:
    • while ((row = mysql_fetch_row(res)) != nullptr)
    • 对每列:
      • field_name = fields[i].name
      • field_value = row[i] ? row[i] : ""(NULL 转空串)
    • result.push_back(row_map)
  7. freeResult(res),last_error_.clear(),返回 result

边界与语义

  • 返回空 vector 并不一定是“查询无结果”,也可能是“执行失败”。
  • 调用方应配合 getError() 判断。

3.3 int DBConnector::execute(const std::string& sql)

  • 作用:执行非查询 SQL(INSERT/UPDATE/DELETE)。

执行步骤

  1. 若 db_ == nullptr:
    • last_error_ = "未连接数据库"
    • 返回 -1
  2. mysql_query(db_, sql.c_str())
    • 失败:last_error_ = "SQL执行失败: " + mysql_error(db_),返回 -1
  3. affected_rows = mysql_affected_rows(db_)
  4. last_error_.clear(),返回 affected_rows

语义

  • 成功返回影响行数(可能为 0)
  • 失败返回 -1

3.4 std::string DBConnector::getError()

  • 作用:返回 last_error_ 的当前值(按值返回副本)。
  • 注意:该函数本身未加锁。

4. 单例生命周期管理

4.1 static void DBConnector::initInstance(...)

  • 作用:初始化单例(若尚未创建)。

执行步骤

  1. std::lock_guard<std::mutex> lock(mutex_)
  2. 若 instance_ == nullptr:
    • instance_ = new DBConnector(...)
    • 若构造抛异常:打印 cerr,保持 instance_ = nullptr
  3. 若 instance_ != nullptr:静默忽略(不重置)

风险点

  • 重复 init 时参数不会更新,可能与调用者预期不一致。

4.2 static DBConnector* DBConnector::getInstance()

  • 作用:获取单例指针。

执行步骤

  1. 加锁 mutex_
  2. 若 instance_ == nullptr:
    • 抛 std::runtime_error("单例未初始化,请先调用initInstance")
  3. 返回 instance_

4.3 static void DBConnector::destroyInstance()

  • 作用:销毁单例。

执行步骤

  1. 加锁 mutex_
  2. 若 instance_ != nullptr:
    • delete instance_
    • instance_ = nullptr

注意

  • 若其他线程仍持有旧指针会悬空,需外部保证生命周期同步。

5. SQL 字符串转义

5.1 static std::string DBConnector::escapeSqlLiteral(const std::string& value)

  • 作用:将字符串字面量中的特殊字符转义,降低拼接 SQL 的注入风险。

处理规则

  • \\ -> \\\\
  • ' -> ''
  • \0 -> \\0
  • \b -> \\b
  • \n -> \\n
  • \r -> \\r
  • \t -> \\t
  • \x1A -> \\Z
  • 其他字符原样追加

关键说明

  • 这是字符串层面的最小防护,不等价于预编译参数绑定。
  • 生产建议优先 prepared statements。

6. 线程安全与并发语义

已加锁部分

  • initInstance
  • getInstance
  • destroyInstance

未加锁部分

  • connect/query/execute/getError
  • 对同一个 MYSQL* 的并发访问未在该类内部同步

面试回答建议

“当前实现将单例创建做了线程安全,但数据库操作层并没有连接池和调用级互斥;高并发场景应改为连接池 + 每连接独占线程或租借模型。”


7. 常见调用链(项目内)

  1. DBConnector::initInstance(...)
  2. DBConnector* db = DBConnector::getInstance()
  3. db->connect()
  4. 读:db->query(sql) / 写:db->execute(sql)
  5. 失败时:db->getError()

8. 已知限制与改进方向

  • 单连接模型,不适合高并发
  • 返回数据全字符串化,类型信息丢失
  • 错误体系是“返回值 + last_error_”,缺统一错误码
  • 无事务封装、无 prepared statement、无超时重连治理

可演进方向:

  • 连接池(min/max/idle/lifetime)
  • prepared statement 与参数绑定
  • 超时、重试、断线重连
  • 统一错误码与可观测指标(慢 SQL、失败率)

下一模块(顺序)

EmailSender → docs/modules/detail/EmailSender_FUNCTIONS.md

全部章节