# databaseManage **Repository Path**: King_xg/database-manage ## Basic Information - **Project Name**: databaseManage - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-27 - **Last Updated**: 2026-06-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # PublicDataManage C++ 数据库管理库 —— 支持 MySQL / SQLite / PostgreSQL 三种数据库,编译为动态库或静态库供外部项目调用。 项目由**两个独立编译的库**组成: - **`DbCore`**(基础库,`namespace DbCore`):通用、可独立复用的数据库访问层,对任何表结构都适用。 - **`PublicDataManage`**(业务库,`namespace PublicDataManage`):依赖 DbCore,封装「6 种业务表 + 按天建表(`前缀_YYYY_MM_DD`)」具体业务,对外提供稳定 API。 ## 项目结构 ``` PublicDataManage/ ├── CMakeLists.txt # 顶层构建脚本(add_subdirectory(core) + 业务库) ├── cmake/ │ └── FindMySQLConnectorCpp.cmake # MySQL Connector/C++ 查找模块 │ ├── core/ # ── DbCore 基础库(通用数据库访问层) ── │ ├── CMakeLists.txt # DbCore 库构建脚本(依赖查找 + 导出宏) │ ├── include/dbcore/ │ │ ├── DbCore.h # 基础库伞头(include 全部对外头) │ │ ├── DbClient.h # 通用客户端(对外核心:持有连接池 + 通用 CRUD/DDL) │ │ ├── SchemaGenerator.h # DDL 生成(建表/改表,方言适配) │ │ ├── SqlBuilder.h # 结构化 SQL 构建工具 │ │ ├── ConfigFile.h # JSON 配置文件解析 │ │ ├── DatabaseTypes.h # 通用类型(ConnectionConfig, QueryResult, FieldMeta 等) │ │ ├── DatabaseException.h # 异常类 │ │ ├── IDatabaseConnection.h # 连接抽象接口 │ │ ├── IDatabaseDriver.h # 驱动工厂接口 │ │ ├── ConnectionPool.h # 线程安全连接池 │ │ ├── MySQLConnection.h / MySQLDriver.h │ │ ├── SQLite3Connection.h / SQLite3Driver.h │ │ ├── PgConnection.h / PgDriver.h │ │ └── ExportConfig.h.in # DBCORE_API 导出宏模板 │ └── src/ # DbCore 实现 + 三数据库驱动实现 │ ├── DbClient.cpp / SchemaGenerator.cpp / SqlBuilder.cpp │ ├── ConnectionPool.cpp / ConfigFile.cpp │ └── MySQL*.cpp / SQLite3*.cpp / Pg*.cpp │ ├── include/ # ── PublicDataManage 业务库(瘦壳,依赖 DbCore) ── │ ├── PublicDataManage.h # 业务库伞头(include dbcore/DbCore.h + 业务头) │ └── business/ │ ├── ExportConfig.h.in # PDM_API 导出宏模板 │ ├── DbCoreTypes.h # DbCore 类型 → PublicDataManage 命名空间桥接(向后兼容) │ ├── TableType.h # 表类型枚举 + 表名工具 │ ├── TableDefs.h # 业务表字段定义 + DDL 转发 │ ├── IDataManager.h # 业务管理器接口 │ ├── SampleData.h / DefectData.h / RejudgeData.h │ ├── RecipeChangeData.h / DeviceAlarmData.h / DeviceWearData.h │ ├── src/business/ # 业务库实现 │ ├── DataManager.h/.cpp # 业务管理器(薄壳:持有 DbCore::DbClient,翻译 + 委托) │ └── TableDefs.cpp # getTableFields + DDL 转发到 SchemaGenerator │ ├── test/ # 接口测试(SQLite 内存库,无外部依赖) ├── test_mysql/ # MySQL 实测套件 └── test_pg/ # PostgreSQL 模拟测试(Mock 驱动 + PG SQL 翻译) ``` ## 架构设计 项目采用**两库架构**:通用能力下沉到 DbCore 基础库,业务层只做「翻译 + 委托」的薄壳: ``` ┌─────────────────────────────────────────────────┐ │ 调用方(外部项目) │ └──────────────────────┬──────────────────────────┘ │ 业务 API(保持不变) ┌──────────────────────▼──────────────────────────┐ │ 业务库 PublicDataManage(namespace 同名) │ │ DataManager —— 薄壳:持有 DbCore::DbClient │ │ insertSample(date,data) → client_.insert( │ │ getTableName(Sample,date), data.toValueMap())│ │ createTable(type,date) → client_.createTable( │ │ getTableName(type,date), getTableFields(type))│ │ (TableType,date) → 表名 / 字段列表 → 委托 DbClient │ └──────────────────────┬──────────────────────────┘ │ 通用调用(表名字符串 + FieldMeta 列表) ┌──────────────────────▼──────────────────────────┐ │ 基础库 DbCore(namespace DbCore) │ │ DbClient —— 通用执行器:SQL 生成/执行 · CRUD │ │ SchemaGenerator —— 建表/改表 DDL(方言适配) │ │ SqlBuilder —— 结构化查询 · ConnectionPool —— 连接池│ └──────────────────────┬──────────────────────────┘ │ ┌────────────┼────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ MySQL │ │ SQLite │ │PostgreSQL│ │Connection│ │Connection│ │Connection│ └──────────┘ └──────────┘ └──────────┘ ``` **核心设计点**: - **两库解耦**:DbCore 不认识任何业务表(只操作「表名字符串 + FieldMeta 列表」),可独立复用;业务库封装「6 种表 + 按天建表」具体语义,依赖 DbCore - **薄壳 DataManager**:业务层方法体仅做 `(TableType, date) → 表名`、`业务结构体 → 字段列表/值映射` 的翻译,再委托 `DbCore::DbClient` 执行 - **抽象工厂模式**:`IDatabaseDriver` → `IDatabaseConnection`,扩展新数据库只需实现两个类 - **线程安全连接池**:预创建 N 个连接,互斥锁 + 条件变量管理获取/归还,自动健康检查 - **表结构与数据结构绑定**:每个数据结构(`SampleData`、`DefectData` 等)提供自己的 `getFieldMetas()` 方法,业务层 `TableDefs.cpp` 委托给各结构体;DDL 方言适配下沉到 `DbCore::SchemaGenerator` - **自动建表**:插入数据时调用 `ensureTableExists()`,表不存在则自动 `CREATE TABLE IF NOT EXISTS` - **SQL 方言适配**:建表/查询/插入自动根据数据库类型切换引号风格、自增语法、类型映射等 - **双套导出宏**:`DBCORE_API`(DbCore)+ `PDM_API`(PublicDataManage),跨平台 dllexport/visibility - **向后兼容**:业务 API(`createDataManager`/`insertSample`/`IDataManager`/`namespace PublicDataManage`/`-lPublicDataManage`)零改动;DbCore 类型通过 `DbCoreTypes.h` 在业务命名空间做 using 别名 ## 业务表说明 支持 **6 种按天建表** 的业务表: | 枚举值 | 表类型 | 前缀 | 表名示例 | | ------ | -------------------- | ---- | ----------------- | | 0 | 样本表 | pd | `pd_2026_05_26` | | 1 | 缺陷表 | df | `df_2026_05_26` | | 2 | 复判表 | rj | `rj_2026_05_26` | | 3 | Recipe 变更表 | rc | `rc_2026_05_26` | | 4 | 设备报警信息表 | dw | `dw_2026_05_26` | | 5 | 设备元器件损耗信息表 | dl | `dl_2026_05_26` | ## 两种使用方式 ### 方式 A:使用业务库 PublicDataManage(6 种业务表 + 按天建表) 包含 ``,调用 `createDataManager()`,API 见下文「快速开始」。 ### 方式 B:直接使用基础库 DbCore(任意表结构) DbCore 是通用层,不绑定业务表,可独立复用。包含 ``,直接使用 `DbCore::DbClient`: ```cpp #include int main() { using namespace DbCore; DbClient client; ConnectionConfig cfg; cfg.dbType = DatabaseType::SQLite; cfg.database = "example.db"; cfg.poolSize = 1; client.init(cfg); // 任意表名 + FieldMeta 列表建表 client.createTable("my_table", { {"id", "INT", true, true}, // 非空 + 主键 {"name", "VARCHAR(255)", false, false}, {"age", "INT", false, false}, }); // 按表名 CRUD(不认识任何业务表) client.insert("my_table", {{"name", "alice"}, {"age", "30"}}); QueryResult r = client.query("my_table", "age > 18"); // 结构化查询 / 更新 / 删除(复用 SqlBuilder) client.update("my_table", {{"age", "0", ConditionOp::GreaterThan}}, {{"name", "adult"}}); client.shutdown(); return 0; } ``` ## 依赖安装 ### 方式一:vcpkg(推荐) ```bash # 安装所需依赖(按需安装,不需要的可以跳过) vcpkg install mysql-connector-cpp # MySQL vcpkg install sqlite3 # SQLite vcpkg install libpq # PostgreSQL ``` ### 方式二:系统包管理器 **Ubuntu / Debian:** ```bash sudo apt install libmysqlcppconn-dev libsqlite3-dev libpq-dev ``` **Windows:** 推荐使用 vcpkg 安装所有依赖。 ## 编译 ### 使用 vcpkg 工具链 ```bash # 配置(自动检测已安装的依赖,启用对应数据库支持) cmake -B build -DCMAKE_TOOLCHAIN_FILE=[vcpkg路径]/scripts/buildsystems/vcpkg.cmake # 编译 cmake --build build --config Release ``` ### 只启用特定数据库 ```bash # 仅 SQLite(无需额外依赖) cmake -B build -DPDM_WITH_MYSQL=OFF -DPDM_WITH_POSTGRESQL=OFF # 仅 MySQL cmake -B build -DPDM_WITH_SQLITE=OFF -DPDM_WITH_POSTGRESQL=OFF # MySQL + PostgreSQL cmake -B build -DPDM_WITH_SQLITE=OFF ``` ### 编译选项 | 选项 | 说明 | 默认值 | | ---- | ---- | ------ | | `PDM_WITH_MYSQL` | 启用 MySQL 支持 | ON | | `PDM_WITH_SQLITE` | 启用 SQLite 支持 | ON | | `PDM_WITH_POSTGRESQL` | 启用 PostgreSQL 支持 | ON | | `BUILD_SHARED_LIBS` | 编译为动态库(否则静态库) | OFF | 如果启用了某种数据库但找不到对应依赖,CMake 会输出警告并自动禁用该数据库支持。**至少需要启用一种数据库。** ### 编译产物 重构后生成**两个库**: | 库 | 产物(Windows) | 产物(Linux/macOS) | 说明 | | -- | --------------- | ------------------- | ---- | | DbCore(基础库) | `DbCore.dll` + `DbCore.lib` | `libDbCore.so` / `libDbCore.a` | 通用数据库访问层,可独立复用 | | PublicDataManage(业务库) | `PublicDataManage.dll` + `PublicDataManage.lib` | `libPublicDataManage.so` / `libPublicDataManage.a` | 业务层,依赖 DbCore | > 业务库已通过 `target_link_libraries(PUBLIC DbCore)` 自动链接基础库,外部项目只需链接 `PublicDataManage` 即可。需要直接使用通用层(不涉及 6 种业务表)时,可单独链接 `DbCore`。 ## 快速开始 ### 1. 包含头文件 ```cpp #include ``` ### 2. 连接数据库 ```cpp using namespace PublicDataManage; // ── MySQL ── ConnectionConfig cfg; cfg.dbType = DatabaseType::MySQL; cfg.host = "127.0.0.1"; cfg.port = 3306; cfg.username = "root"; cfg.password = "123456"; cfg.database = "production_data"; cfg.createDatabase = true; // 数据库不存在时自动创建 // ── SQLite ── ConnectionConfig cfg; cfg.dbType = DatabaseType::SQLite; cfg.database = "C:/data/production.db"; // 数据库文件路径(":memory:" 为内存数据库) cfg.poolSize = 1; // SQLite 建议连接池设为 1 // SQLite 不需要 createDatabase,文件不存在时自动创建 // ── PostgreSQL ── ConnectionConfig cfg; cfg.dbType = DatabaseType::PostgreSQL; cfg.host = "127.0.0.1"; cfg.port = 5432; cfg.username = "postgres"; cfg.password = "123456"; cfg.database = "production_data"; cfg.createDatabase = true; // 数据库不存在时自动创建 ``` ### 3. 完整使用示例(覆盖所有 API 方法) ```cpp #include #include #include int main() { using namespace PublicDataManage; // ════════════════════════════════════════ // 1. 创建管理器 + 初始化 // ════════════════════════════════════════ auto mgr = createDataManager(); ConnectionConfig cfg; cfg.dbType = DatabaseType::SQLite; cfg.database = "test.db"; cfg.poolSize = 1; try { mgr->init(cfg); std::cout << "[init] 数据库连接成功" << std::endl; } catch (const DatabaseException& e) { std::cerr << "[init] 失败: " << e.what() << std::endl; return 1; } const std::string date = "2026_05_26"; // ════════════════════════════════════════ // 2. insertSample — 插入样本数据(自动建表 pd_2026_05_26) // ════════════════════════════════════════ { SampleData sample; sample.id = 1; sample.recipeName = "配方A"; sample.qrcode = "QR001"; sample.sampleLevel = 1; sample.rejudgeRlt = "-1"; sample.datetime = 1748246400; sample.laneNum = "1"; sample.productId = 100; sample.extendedAttributes = R"({"workstation":"WS01"})"; sample.measurementInformation = R"({"width":10.5})"; sample.traceInformation = R"({"mes_rlt":"OK"})"; sample.otherInformation = "{}"; int64_t id = mgr->insertSample(date, sample); std::cout << "[insertSample] ID = " << id << std::endl; } // ════════════════════════════════════════ // 3. insertDefect — 插入缺陷数据(自动建表 df_2026_05_26) // ════════════════════════════════════════ { DefectData defect; defect.id = 1; defect.sampleId = 1; defect.stationNum = 3; defect.laneNum = 1; defect.datetime = "2026-05-26 10:30:00"; defect.defectType = "scratch"; defect.defectTag = "surface_scratch"; defect.defectParentTag = "surface"; defect.defectLevel = 2; defect.defectQuality = 1; defect.defectAbType = "A"; defect.defectConfidence = 0.95; defect.defectRegion = "top_center"; defect.channelName = "CH01"; defect.defectLength = 12.5f; defect.defectWidth = 3.2f; defect.defectArea = 40.0f; defect.extendedAttributes = R"({"color":"white"})"; defect.mlResult = R"({"model":"v2","score":0.95})"; defect.otherInformation = "{}"; int64_t id = mgr->insertDefect(date, defect); std::cout << "[insertDefect] ID = " << id << std::endl; } // ════════════════════════════════════════ // 4. insertRejudge — 插入复判数据(自动建表 rj_2026_05_26) // ════════════════════════════════════════ { RejudgeData rejudge; rejudge.id = 1; rejudge.belongsId = 100; rejudge.datetime = "2026-05-26 10:00:00"; rejudge.rejudgeDatetime = "2026-05-26 11:30:00"; rejudge.belongsRegionType = 1; rejudge.channelName = "CH01"; rejudge.rejudgeAdd = 0; rejudge.rejudgeType = "manual"; rejudge.rejudgeTypeSec = "operator_review"; rejudge.rejudgeRlt = 1; rejudge.batch = 20260526; rejudge.actionType = 1; rejudge.rejudgeOdsData = R"({"features":[]})"; int64_t id = mgr->insertRejudge(date, rejudge); std::cout << "[insertRejudge] ID = " << id << std::endl; } // ════════════════════════════════════════ // 5. insertRecipeChange — 插入 Recipe 变更数据(自动建表 rc_2026_05_26) // ════════════════════════════════════════ { RecipeChangeData recipe; recipe.id = 1; recipe.moduleName = "检测模块"; recipe.recipeName = "配方A_V2.0"; recipe.version = "2.0.1"; recipe.dateTime = "2026-05-26 14:00:00"; recipe.operation = 2; recipe.user = "admin"; recipe.log = R"({"changes":["updated threshold"]})"; int64_t id = mgr->insertRecipeChange(date, recipe); std::cout << "[insertRecipeChange] ID = " << id << std::endl; } // ════════════════════════════════════════ // 6. insertDeviceAlarm — 插入设备报警数据(自动建表 dw_2026_05_26) // ════════════════════════════════════════ { DeviceAlarmData alarm; alarm.id = 1; alarm.alarmId = "ALM-001"; alarm.alarmLevel = 3; alarm.alarmState = "active"; alarm.alarmInfo = "温度超过阈值"; alarm.alarmCode = 5001; alarm.startTime = "2026-05-26 08:00:00"; alarm.endTime = "2026-05-26 08:05:30"; alarm.totalTime = 330000; alarm.curState = "alarm"; alarm.preState = "running"; alarm.machineStation = "WS-03"; alarm.solution = "检查散热风扇"; int64_t id = mgr->insertDeviceAlarm(date, alarm); std::cout << "[insertDeviceAlarm] ID = " << id << std::endl; } // ════════════════════════════════════════ // 7. insertDeviceWear — 插入设备元器件损耗数据(自动建表 dl_2026_05_26) // ════════════════════════════════════════ { DeviceWearData wear; wear.id = 1; wear.moduleName = "光源模块"; wear.partName = "LED灯珠"; wear.partNo = "PN-LED-001"; wear.partSpec = "5050白光 6000K"; wear.partDes = "检测工位主光源"; wear.station = "WS-01"; wear.total = 10000; wear.type = 1; wear.used = 7500; wear.user = "维护员A"; wear.warning = 9000; wear.dateTime = "2026-05-26 09:00:00"; int64_t id = mgr->insertDeviceWear(date, wear); std::cout << "[insertDeviceWear] ID = " << id << std::endl; } // ════════════════════════════════════════ // 8. query — 查询数据 // ════════════════════════════════════════ // 8a. 查全部 { QueryResult result = mgr->query(TableType::Sample, date); std::cout << "[query] 样本表共 " << result.size() << " 条" << std::endl; for (const auto& row : result.rows) { std::cout << " id=" << row.at("id") << " recipe=" << row.at("recipe_name") << " qrcode=" << row.at("qrcode") << std::endl; } } // 8b. 条件查询(不含 WHERE 关键字) { QueryResult result = mgr->query(TableType::Sample, date, "sample_level = 1"); std::cout << "[query] sample_level=1 的有 " << result.size() << " 条" << std::endl; } // 8c. 指定列查询(不传 columns → SELECT *) { QueryResult result = mgr->query(TableType::Sample, date, "", {}); // 生成: SELECT * FROM "pd_2026_05_26" } // 8d. 自定义列名查询(只查指定列,减少数据传输) { QueryResult result = mgr->query(TableType::Sample, date, "", {"recipe_name", "qrcode", "sample_level"}); // 生成: SELECT "recipe_name", "qrcode", "sample_level" FROM "pd_2026_05_26" std::cout << "[query] 指定3列,共 " << result.size() << " 条" << std::endl; for (const auto& row : result.rows) { std::cout << " recipe=" << row.at("recipe_name") << " qrcode=" << row.at("qrcode") << " level=" << row.at("sample_level") << std::endl; } } // 8e. 自定义列名 + WHERE 条件 { QueryResult result = mgr->query(TableType::Sample, date, "product_id = 100", {"id", "recipe_name", "qrcode"}); // 生成: SELECT "id", "recipe_name", "qrcode" FROM "pd_2026_05_26" WHERE product_id = 100 std::cout << "[query] 指定列+条件,共 " << result.size() << " 条" << std::endl; } // 8f. 查缺陷表 { QueryResult result = mgr->query(TableType::Defect, date, "defect_level >= 2"); std::cout << "[query] 严重缺陷 " << result.size() << " 条" << std::endl; } // 8g. 查复判表 { QueryResult result = mgr->query(TableType::Rejudge, date, "rejudge_rlt = 1"); std::cout << "[query] 复判OK的 " << result.size() << " 条" << std::endl; } // 8h. 查 Recipe 变更表 { QueryResult result = mgr->query(TableType::RecipeChange, date); std::cout << "[query] Recipe变更 " << result.size() << " 条" << std::endl; } // 8i. 查设备报警表 { QueryResult result = mgr->query(TableType::DeviceAlarm, date, "alarmLevel = 3"); std::cout << "[query] 严重报警 " << result.size() << " 条" << std::endl; } // 8j. 查设备元器件损耗表 { QueryResult result = mgr->query(TableType::DeviceWear, date, "used >= warning"); std::cout << "[query] 需更换元器件 " << result.size() << " 条" << std::endl; } // ════════════════════════════════════════ // 9. update — 修改数据 // ════════════════════════════════════════ // 9a. 修改样本的复判结果 { std::map updates; updates["rejudge_rlt"] = "1"; updates["sample_level"] = "2"; int affected = mgr->update(TableType::Sample, date, "id = 1", updates); std::cout << "[update] 修改样本 " << affected << " 行" << std::endl; } // 9b. 修改设备报警状态 { std::map updates; updates["alarm_state"] = "resolved"; updates["end_time"] = "2026-05-26 09:00:00"; int affected = mgr->update(TableType::DeviceAlarm, date, "alarm_id = 'ALM-001'", updates); std::cout << "[update] 修改报警 " << affected << " 行" << std::endl; } // 9c. 使用数据结构的 toValueMap() 修改(可只填需要改的字段) { SampleData partial; partial.sampleLevel = 3; partial.otherInformation = R"({"note":"升级等级"})"; // toValueMap() 会返回所有字段,只想改部分字段时建议用上面 9a 的方式 // 或从 toValueMap() 中筛选需要的字段 auto allFields = partial.toValueMap(); std::map partialUpdate; partialUpdate["sample_level"] = allFields["sample_level"]; partialUpdate["other_information"] = allFields["other_information"]; int affected = mgr->update(TableType::Sample, date, "qrcode = 'QR001'", partialUpdate); std::cout << "[update] 部分字段修改 " << affected << " 行" << std::endl; } // ════════════════════════════════════════ // 10. remove — 删除数据 // ════════════════════════════════════════ // 10a. 按主键删除 { int deleted = mgr->remove(TableType::Defect, date, "id = 999"); std::cout << "[remove] 删除缺陷 " << deleted << " 行" << std::endl; } // 10b. 按条件批量删除 { int deleted = mgr->remove(TableType::Sample, date, "sample_level = -1"); std::cout << "[remove] 删除无效样本 " << deleted << " 行" << std::endl; } // 10c. 删除指定时间范围的数据 { int deleted = mgr->remove(TableType::DeviceAlarm, date, "start_time < '2026-05-26 06:00:00'"); std::cout << "[remove] 删除早期报警 " << deleted << " 行" << std::endl; } // ════════════════════════════════════════ // 11. 结构化查询(无需手写 SQL) // ════════════════════════════════════════ // 11a. Equal 条件查询 { QueryParam param; param.conditions = {{"sample_level", "1", ConditionOp::Equal}}; auto result = mgr->query(TableType::Sample, date, param); std::cout << "[structured query] sample_level=1 的有 " << result.size() << " 条" << std::endl; } // 11b. LIKE 模糊查询 + 排序 + 限制条数 { QueryParam param; param.conditions = {{"recipe_name", "%配方%", ConditionOp::Like}}; param.orderColumn = "id"; param.orderAsc = false; param.limit = 10; auto result = mgr->query(TableType::Sample, date, param); std::cout << "[structured query] 模糊匹配 " << result.size() << " 条" << std::endl; } // 11c. 结构化更新 { int affected = mgr->update(TableType::Sample, date, {{"qrcode", "QR001", ConditionOp::Equal}}, {{"sample_level", "2"}}); std::cout << "[structured update] 修改 " << affected << " 行" << std::endl; } // 11d. 结构化删除 { // 先插入一条用于删除 SampleData del; del.id = 999; del.recipeName = "ToDelete"; del.qrcode = "DEL"; del.sampleLevel = 0; del.datetime = 0; mgr->insertSample(date, del); int deleted = mgr->remove(TableType::Sample, date, {{"id", "999", ConditionOp::Equal}}); std::cout << "[structured delete] 删除 " << deleted << " 行" << std::endl; } // ════════════════════════════════════════ // 12. executeQuery — 执行任意 SELECT // ════════════════════════════════════════ // ════════════════════════════════════════ { // 统计查询 auto stats = mgr->executeQuery( R"(SELECT COUNT(*) AS total FROM "pd_2026_05_26")" ); if (!stats.empty()) { std::cout << "[executeQuery] 样本总数: " << stats.rows[0].at("total") << std::endl; } // 联表查询 auto joinResult = mgr->executeQuery( R"(SELECT s.id, s.recipe_name, d.defect_type FROM "pd_2026_05_26" s )" R"(JOIN "df_2026_05_26" d ON s.id = d.sample_id WHERE d.defect_level >= 2)" ); std::cout << "[executeQuery] 联表查出 " << joinResult.size() << " 条" << std::endl; } // ════════════════════════════════════════ // 13. executeUpdate — 执行 UPDATE / DELETE / DDL // ════════════════════════════════════════ { // UPDATE int affected = mgr->executeUpdate( R"(UPDATE "pd_2026_05_26" SET rejudge_rlt = '1' WHERE id = 1)" ); std::cout << "[executeUpdate] UPDATE 影响 " << affected << " 行" << std::endl; // DELETE int deleted = mgr->executeUpdate( R"(DELETE FROM "pd_2026_05_26" WHERE sample_level = -1)" ); std::cout << "[executeUpdate] DELETE 影响 " << deleted << " 行" << std::endl; } // ════════════════════════════════════════ // 14. executeInsert — 执行自定义 INSERT // ════════════════════════════════════════ { int64_t id = mgr->executeInsert( R"(INSERT INTO "pd_2026_05_26" (id, recipe_name, qrcode, sample_level, )" R"(rejudge_rlt, datetime, lane_num, product_id) )" R"(VALUES (2, '配方B', 'QR002', 0, '-1', 1748246400, '2', 200))" ); std::cout << "[executeInsert] 自定义插入 ID = " << id << std::endl; } // ════════════════════════════════════════ // 15. createTable — 手动建表 // ════════════════════════════════════════ { // 提前创建未来日期的表 mgr->createTable(TableType::Sample, "2026_05_27"); std::cout << "[createTable] 已创建 pd_2026_05_27" << std::endl; // 创建所有类型的表 mgr->createTable(TableType::Defect, "2026_05_27"); mgr->createTable(TableType::Rejudge, "2026_05_27"); mgr->createTable(TableType::RecipeChange, "2026_05_27"); mgr->createTable(TableType::DeviceAlarm, "2026_05_27"); mgr->createTable(TableType::DeviceWear, "2026_05_27"); std::cout << "[createTable] 已创建 2026_05_27 全部 6 种表" << std::endl; } // ════════════════════════════════════════ // 16. ensureTableExists — 确保表存在 // ════════════════════════════════════════ { // 表已存在时不执行任何操作 mgr->ensureTableExists(TableType::Sample, "2026_05_26"); std::cout << "[ensureTableExists] pd_2026_05_26 确认存在" << std::endl; // 表不存在时自动创建 mgr->ensureTableExists(TableType::Sample, "2026_06_01"); std::cout << "[ensureTableExists] pd_2026_06_01 已创建(不存在则创建)" << std::endl; } // ════════════════════════════════════════ // 17. updateTableSchema — 更新表结构 // ════════════════════════════════════════ { // 对比表定义与实际列,自动补充缺失列 auto sqls = mgr->updateTableSchema(TableType::Sample, date); if (sqls.empty()) { std::cout << "[updateTableSchema] 表结构已最新,无需更新" << std::endl; } else { std::cout << "[updateTableSchema] 执行了 " << sqls.size() << " 条 ALTER:" << std::endl; for (const auto& sql : sqls) { std::cout << " " << sql << std::endl; } } } // ════════════════════════════════════════ // 18. 工具函数:getTableName / getTablePrefix // ════════════════════════════════════════ { std::cout << "[getTableName] 样本表: " << getTableName(TableType::Sample, "2026_05_26") << std::endl; std::cout << "[getTableName] 缺陷表: " << getTableName(TableType::Defect, "2026_05_26") << std::endl; std::cout << "[getTableName] 复判表: " << getTableName(TableType::Rejudge, "2026_05_26") << std::endl; std::cout << "[getPrefix] Sample=" << getTablePrefix(TableType::Sample) << " Defect=" << getTablePrefix(TableType::Defect) << " Rejudge=" << getTablePrefix(TableType::Rejudge) << " Recipe=" << getTablePrefix(TableType::RecipeChange) << " Alarm=" << getTablePrefix(TableType::DeviceAlarm) << " Wear=" << getTablePrefix(TableType::DeviceWear) << std::endl; } // ════════════════════════════════════════ // 19. shutdown — 关闭管理器 // ════════════════════════════════════════ mgr->shutdown(); std::cout << "[shutdown] 已关闭数据库连接" << std::endl; return 0; } ``` #### 预期输出 ``` [init] 数据库连接成功 [insertSample] ID = 1 [insertDefect] ID = 1 [insertRejudge] ID = 1 [insertRecipeChange] ID = 1 [insertDeviceAlarm] ID = 1 [insertDeviceWear] ID = 1 [query] 样本表共 1 条 id=1 recipe=配方A qrcode=QR001 [query] sample_level=1 的有 1 条 [query] 指定3列,共 1 条 recipe=配方A qrcode=QR001 level=1 [query] 指定列+条件,共 1 条 [query] 严重缺陷 1 条 [query] 复判OK的 1 条 [query] Recipe变更 1 条 [query] 严重报警 1 条 [query] 需更换元器件 0 条 [update] 修改样本 1 行 [update] 修改报警 1 行 [update] 部分字段修改 1 行 [remove] 删除缺陷 0 行 [remove] 删除无效样本 0 行 [remove] 删除早期报警 0 行 [executeQuery] 样本总数: 1 [executeQuery] 联表查出 1 条 [executeUpdate] UPDATE 影响 1 行 [executeUpdate] DELETE 影响 0 行 [executeInsert] 自定义插入 ID = 2 [createTable] 已创建 pd_2026_05_27 [createTable] 已创建 2026_05_27 全部 6 种表 [ensureTableExists] pd_2026_05_26 确认存在 [ensureTableExists] pd_2026_06_01 已创建(不存在则创建) [updateTableSchema] 表结构已最新,无需更新 [getTableName] 样本表: pd_2026_05_26 [getTableName] 缺陷表: df_2026_05_26 [getTableName] 复判表: rj_2026_05_26 [getPrefix] Sample=pd Defect=df Rejudge=rj Recipe=rc Alarm=dw Wear=dl [shutdown] 已关闭数据库连接 ``` ## API 参考 ### IDataManager 接口 ```cpp class IDataManager { public: // 初始化(根据 config.dbType 自动选择驱动) void init(const ConnectionConfig& config); // 关闭管理器 void shutdown(); // 插入(date 格式 "YYYY_MM_DD",插入时自动建表) int64_t insertSample(const std::string& date, const SampleData& data); int64_t insertDefect(const std::string& date, const DefectData& data); int64_t insertRejudge(const std::string& date, const RejudgeData& data); int64_t insertRecipeChange(const std::string& date, const RecipeChangeData& data); int64_t insertDeviceAlarm(const std::string& date, const DeviceAlarmData& data); int64_t insertDeviceWear(const std::string& date, const DeviceWearData& data); // 查询(condition 为 WHERE 后的条件,不含 WHERE 关键字) // columns 可选,为空则查询所有列(SELECT *),非空则只查指定列 QueryResult query(TableType type, const std::string& date, const std::string& condition = "", const std::vector& columns = {}); // 修改(values 为要更新的列名-值映射,condition 不能为空) int update(TableType type, const std::string& date, const std::string& condition, const std::map& values); // 删除(condition 不能为空,防止误删全表) int remove(TableType type, const std::string& date, const std::string& condition); // 结构化查询(无需手写 SQL,通过 QueryParam 传递条件/排序/分页) QueryResult query(TableType type, const std::string& date, const QueryParam& queryParams); // 结构化更新(通过 QueryConditions 传递 WHERE 条件) int update(TableType type, const std::string& date, const QueryConditions& conditions, const std::map& values); // 结构化删除(通过 QueryConditions 传递 WHERE 条件) int remove(TableType type, const std::string& date, const QueryConditions& conditions); // 通用 SQL 执行(接收任意 SQL 语句) QueryResult executeQuery(const std::string& sql); // SELECT int executeUpdate(const std::string& sql); // UPDATE / DELETE / DDL int64_t executeInsert(const std::string& sql); // INSERT // 建表 void createTable(TableType type, const std::string& date); void ensureTableExists(TableType type, const std::string& date); // 表结构更新(对比已有列,自动补充缺失列) std::vector updateTableSchema(TableType type, const std::string& date); }; ``` ### 工厂函数 ```cpp // 创建管理器实例 std::unique_ptr createDataManager(); ``` ### 表名生成工具 ```cpp // 根据表类型获取前缀 const char* getTablePrefix(TableType type); // 根据表类型和日期生成完整表名 std::string getTableName(TableType type, const std::string& date); // 例: getTableName(TableType::Sample, "2026_05_26") → "pd_2026_05_26" ``` ### ConnectionConfig 字段 | 字段 | 类型 | 说明 | | ---- | ---- | ---- | | `dbType` | `DatabaseType` | 数据库类型(MySQL / SQLite / PostgreSQL) | | `host` | `string` | 主机地址(MySQL / PostgreSQL) | | `port` | `uint16_t` | 端口号,默认 3306 | | `username` | `string` | 用户名(MySQL / PostgreSQL) | | `password` | `string` | 密码(MySQL / PostgreSQL) | | `database` | `string` | 数据库名;SQLite 时为文件路径 | | `charset` | `string` | 字符集,默认 utf8mb4 | | `createDatabase` | `bool` | 连接时若数据库不存在是否自动创建,默认 false | | `poolSize` | `int` | 连接池大小,默认 5(SQLite 建议设为 1) | | `connectTimeout` | `int` | 连接超时(秒),默认 10 | ### QueryResult 结构 | 字段 | 类型 | 说明 | | ---- | ---- | ---- | | `rows` | `vector>` | 查询结果行(列名 → 值) | | `affectedRows` | `int` | 受影响行数 | | `lastInsertId` | `int64_t` | 最后插入的自增 ID | ### 结构化查询参数 #### ConditionOp 枚举 | 值 | SQL 操作 | 说明 | | -- | -------- | ---- | | `Equal` | `=` | 等于 | | `NotEqual` | `!=` | 不等于 | | `Like` | `LIKE` | 模糊匹配 | | `NotLike` | `NOT LIKE` | 模糊排除 | | `GreaterThan` | `>` | 大于 | | `LessThan` | `<` | 小于 | | `GreaterEqual` | `>=` | 大于等于 | | `LessEqual` | `<=` | 小于等于 | | `In` | `IN (...)` | 包含 | | `IsNull` | `IS NULL` | 为空 | | `IsNotNull` | `IS NOT NULL` | 不为空 | | `Between` | (使用 RangeCondition) | 范围 | | `NoValue` | 直接使用 columnName | 原始条件片段 | #### QueryParam 结构 | 字段 | 类型 | 说明 | | ---- | ---- | ---- | | `tableNames` | `vector` | 多表时用 UNION ALL | | `selectColumns` | `vector` | 空 = SELECT * | | `conditions` | `QueryConditions` | WHERE 条件列表 | | `rangeCondition` | `RangeCondition` | BETWEEN 范围条件 | | `groupColumn` | `string` | GROUP BY 列名 | | `orderColumn` | `string` | ORDER BY 列名 | | `orderAsc` | `bool` | true: 升序, false: 降序 | | `limit` | `int` | 限制条数(0 = 不限制) | ## 在外部项目中使用 ### CMake 集成 ```cmake # 方式一:add_subdirectory(业务库会自动带上 DbCore 依赖) add_subdirectory(path/to/PublicDataManage) target_link_libraries(YourApp PRIVATE PublicDataManage) # 业务库(含 6 种业务表) # 或只用基础库: target_link_libraries(YourApp PRIVATE DbCore) # 基础库(通用,任意表结构) # 方式二:install 后 find_package find_package(PublicDataManage REQUIRED) target_link_libraries(YourApp PRIVATE PublicDataManage::PublicDataManage) # find_package(DbCore REQUIRED) # target_link_libraries(YourApp PRIVATE DbCore::DbCore) ``` ### 编译命令 ```bash # 动态库(业务库依赖基础库,需同时链接) g++ -std=c++17 main.cpp -L./build -lPublicDataManage -lDbCore -o app # 静态库 g++ -std=c++17 main.cpp ./build/libPublicDataManage.a ./build/core/libDbCore.a -o app ``` ## 技术要求 - **C++ 标准**:C++17 - **CMake 最低版本**:3.16 - **编译器**:MSVC 2019+ / GCC 8+ / Clang 10+ - **平台**:Windows / Linux