# 数据库连接管理 **本文引用的文件** - [IOManager.h](file://h/IOManager.h) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp) - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp) - [msado15.tlh](file://Release/msado15.tlh) - [msado15.tli](file://Release/msado15.tli) - [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp) - [TdManager.cpp](file://cpp/Managers/TdManager.cpp) - [ProManager.cpp](file://cpp/Managers/ProManager.cpp) - [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp) - [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) ## 简介 本文件聚焦于基于ADO(ActiveX Data Objects)的数据库连接管理,围绕CIOManager类在GeomativeStudio中的职责展开,系统性说明其如何初始化并管理与Access数据库(.accdb)的连接,涵盖连接字符串配置、事务与命令执行、连接生命周期管理、异常处理与恢复、以及多线程场景下的同步注意事项。同时结合实际代码路径,给出连接建立、健康检查与异常恢复的实现要点,并提供性能调优建议与资源释放策略,帮助读者在不直接阅读源码的情况下理解整体机制。 ## 项目结构 - 应用程序入口负责COM初始化、数据库连接创建与打开、以及各业务管理器实例化。 - CIOManager作为数据导入导出的核心协调者,持有主数据库连接与目录对象,负责导出新数据库、批量写入与事务控制。 - 多个业务管理器(如CTdManager、CProManager等)共享主连接,执行各自的数据操作。 - ADO类型头文件提供Connection/Command/Recordset等接口属性与方法声明,便于理解超时、隔离级别、状态等能力。 ```mermaid graph TB App["应用程序入口
初始化COM/创建连接"] --> Conn["_ConnectionPtr
主连接"] App --> Catalog["ADOX::_CatalogPtr
目录对象"] Conn --> IO["CIOManager
导入/导出协调"] Conn --> TdMgr["CTdManager
TD相关操作"] Conn --> ProMgr["CProManager
项目/区域操作"] Conn --> SptOp["CSptOperator
测点/脚本操作"] Conn --> DataOp["CDataOperator
数据删除/更新"] Conn --> Test["CProblemZone::TestingData
测试数据写入"] ``` 图表来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L309) - [IOManager.h](file://h/IOManager.h#L15-L51) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L256) - [msado15.tlh](file://Release/msado15.tlh#L3990-L4029) 章节来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L309) - [IOManager.h](file://h/IOManager.h#L15-L51) ## 核心组件 - CIOManager:负责导入/导出流程的协调,持有主连接与目录对象;导出时创建新的目标数据库并批量写入,使用事务保证一致性。 - 主连接(_ConnectionPtr):由应用程序入口创建并打开,承载所有业务操作。 - 目录对象(ADOX::_CatalogPtr):用于创建新数据库、定义表结构与列约束。 - 命令对象(_CommandPtr):在事务内执行SQL语句,绑定ActiveConnection,避免重复创建连接。 - 记录集(_RecordsetPtr):用于查询、更新、参数化查询等。 章节来源 - [IOManager.h](file://h/IOManager.h#L15-L51) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L256) - [msado15.tlh](file://Release/msado15.tlh#L3990-L4029) ## 架构总览 下图展示了应用启动时的连接初始化与关键业务流程之间的交互关系。 ```mermaid sequenceDiagram participant App as "应用程序入口" participant Conn as "_ConnectionPtr" participant Cat as "ADOX : : _CatalogPtr" participant IO as "CIOManager" participant Td as "CTdManager" participant Pro as "CProManager" participant Spt as "CSptOperator" participant Data as "CDataOperator" App->>App : 初始化COM App->>Conn : 创建连接实例 App->>Conn : 打开连接(连接字符串) App->>Cat : 设置活动连接/创建数据库 App->>IO : 传入主连接与目录对象 IO->>IO : 导出流程(事务/批量写入) App->>Td : 使用主连接执行TD相关操作 App->>Pro : 使用主连接执行项目/区域操作 App->>Spt : 使用主连接执行测点/脚本操作 App->>Data : 使用主连接执行数据删除/更新 ``` 图表来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L309) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L256) - [IOManager.h](file://h/IOManager.h#L15-L51) ## 详细组件分析 ### CIOManager类与连接管理 - 连接注入:构造函数接收主连接与目录对象,确保后续导出流程可直接复用现有连接。 - 导入流程: - 弹窗选择外部Access文件,拼接连接字符串(包含提供程序与数据库密码),创建连接并打开。 - 检查目标数据库是否包含特定版本表,否则提示错误并回滚。 - 在主连接上开启事务,依次导入项目、区域、测点、响应/电阻率数据,最后提交或回滚。 - 导出流程: - 创建新数据库(通过目录对象),定义项目、区域、TD、TD头、参数、响应/电阻率、IPSP、GR、Scon、Channel、Script、dbversion等表及列。 - 在新连接上开启事务,按树形结构批量导出数据,最后提交并关闭连接。 - 关键点: - 所有命令对象(_CommandPtr)均将ActiveConnection指向主连接,减少连接创建成本。 - 导入/导出均使用事务,失败时回滚并清理临时文件。 ```mermaid classDiagram class CIOManager { +Import() UINT +Export() UINT -CreateExpDatabase(szFileName) _ConnectionPtr -ExportDataToAccdbFile(pExpConnection, dmsTree) void -ExportProjectToAccdbFile(pExpConnection, dwProID) void -ExportTzToAccdbFile(pExpConnection, dwTzID) void -ExportRspTdToAccdbFile(pExpConnection, dwTdID) void -ExportIpspTdToAccdbFile(pExpConnection, dwTdID) void -ExportSptToAccdbFile(pExpConnection, sptList) void -ExportTdHeadInfoToAccdbFile(pExpConnection, dwTdID, szTdName, szDeSn) void -ImportProjectToDB(pImpConnection) void -ImportTzToDB(pImpConnection) void -ImportRspTdToDB(pImpConnection) void -ImportIpspTdToDB(pImpConnection) void -ImportSptToDB(pImpConnection) void -InitialExpDmsTree(dmsTree) void -InitialExpSptList(sptList) void -m_pConnection : _ConnectionPtr -m_pCatalog : ADOX : : _CatalogPtr } ``` 图表来源 - [IOManager.h](file://h/IOManager.h#L15-L51) 章节来源 - [IOManager.h](file://h/IOManager.h#L15-L51) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L101-L204) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L656) ### 应用程序启动与关闭时的连接处理 - 启动阶段: - 初始化COM后创建主连接实例,拼接连接字符串(提供程序、数据源、数据库密码),打开连接。 - 设置Jet OLEDB锁数量上限,提升并发写入能力。 - 创建目录对象并设置活动连接,为导出创建新数据库做准备。 - 实例化各业务管理器(CTdManager、CProManager、CSptOperator等),统一使用主连接。 - 关闭阶段: - 代码中未见显式析构关闭主连接的逻辑。建议在应用退出前显式Close()并置空指针,防止资源泄漏。 ```mermaid flowchart TD Start(["应用启动"]) --> InitCOM["初始化COM"] InitCOM --> CreateConn["创建主连接实例"] CreateConn --> OpenConn["打开连接(连接字符串)"] OpenConn --> SetProps["设置Jet OLEDB属性"] SetProps --> CreateCat["创建目录对象并设置活动连接"] CreateCat --> NewMgrs["实例化业务管理器(共享主连接)"] NewMgrs --> Ready(["就绪"]) Ready --> Shutdown(["应用退出"]) --> CloseConn["关闭主连接(建议)"] CloseConn --> End(["结束"]) ``` 图表来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L309) - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L426-L431) 章节来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L309) - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L426-L431) ### 连接字符串配置与数据库密码 - 主连接字符串包含提供程序、数据源与数据库密码,确保访问受保护的数据库文件。 - 导出目标数据库同样使用相同提供程序与密码策略,保证一致性。 章节来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L284) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L218-L223) ### 事务与批量写入 - 导入:在主连接上BeginTrans,逐项导入后Commit;若异常则Rollback并关闭外部连接。 - 导出:在新连接上BeginTrans,批量写入后Commit;异常时Rollback并删除临时文件。 - 命令对象(_CommandPtr)统一绑定ActiveConnection,减少连接创建与上下文切换。 章节来源 - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L104) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1392-L1448) - [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp#L704-L711) ### 连接生命周期管理 - 生命周期: - 创建:应用程序入口创建主连接实例。 - 打开:使用连接字符串打开连接。 - 使用:各业务模块共享主连接执行查询/更新。 - 关闭:建议在应用退出前显式Close()并置空指针。 - 资源释放: - 记录集、命令对象在使用完毕后应关闭或释放,避免句柄泄露。 - 导出失败时删除临时文件,确保磁盘空间与一致性。 章节来源 - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L104) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L256) ### 多线程环境下的连接同步机制 - 当前代码未显式使用互斥量或临界区保护ADO连接。由于ADO连接对象并非线程安全,跨线程访问存在风险。 - 建议: - 为主连接加全局互斥或在业务层串行化关键操作。 - 对频繁写入的场景,考虑拆分连接或使用只读连接用于查询,写入使用独立连接。 - 避免在UI线程长时间占用连接,必要时将耗时操作移至后台线程并做好异常捕获与回滚。 章节来源 - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1392-L1448) - [Global.cpp](file://cpp/Main/Global.cpp#L48-L58) ### 连接超时设置 - ADO支持ConnectionTimeout与CommandTimeout属性,可通过类型头文件提供的接口设置。 - 实践建议: - 对长事务或大批量写入,适当提高CommandTimeout。 - 对网络型数据库或远程文件,合理设置ConnectionTimeout,避免阻塞UI线程。 章节来源 - [msado15.tlh](file://Release/msado15.tlh#L3990-L4029) - [msado15.tli](file://Release/msado15.tli#L1925-L1954) ### 健康检查与异常恢复 - 健康检查: - 可通过查询版本表或执行简单SQL验证连接可用性。 - 监控连接状态(State属性)与错误集合(Errors)。 - 异常恢复: - 导入/导出均使用try/catch捕获_com_error,失败时Rollback、Close并清理临时文件。 - 对外部数据库校验失败时,提示用户并终止流程。 ```mermaid flowchart TD Start(["开始操作"]) --> Try["尝试执行SQL/事务"] Try --> Ok{"成功?"} Ok --> |是| Commit["提交事务/关闭连接"] Ok --> |否| Catch["捕获_com_error"] Catch --> Rollback["回滚事务/关闭连接"] Rollback --> Clean["清理临时文件/资源"] Clean --> Notify["提示用户/记录日志"] Notify --> End(["结束"]) ``` 图表来源 - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L101-L204) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1392-L1448) - [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp#L704-L711) 章节来源 - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L101-L204) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1392-L1448) - [SptOperator.cpp](file://cpp/Operator/SptOperator.cpp#L704-L711) ### 典型业务流程示例(代码路径) - 导入外部数据库并写入主库: - 连接字符串拼接与打开:[GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L284) - 版本表校验与事务控制:[IOManager.cpp](file://cpp/Managers/IOManager.cpp#L101-L199) - 写入命令绑定ActiveConnection:[IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1418-L1422) - 导出新数据库并批量写入: - 创建数据库与表结构:[IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L656) - 事务内批量写入:[IOManager.cpp](file://cpp/Managers/IOManager.cpp#L658-L727) - 删除TD相关数据: - 查询与删除命令绑定ActiveConnection:[TdManager.cpp](file://cpp/Managers/TdManager.cpp#L6452-L6482) - 更新测试数据: - 参数化更新命令:[TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L365-L405) 章节来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L284) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L101-L199) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L727) - [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L6452-L6482) - [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L365-L405) ## 依赖关系分析 - 组件耦合: - CIOManager依赖主连接与目录对象,承担导入/导出协调职责。 - 各业务管理器(CTdManager、CProManager、CSptOperator、CDataOperator)共享主连接,降低连接数。 - 外部依赖: - ADO/ADOX类型头文件提供Connection/Command/Recordset等接口能力。 - 提供程序为Microsoft.ACE.OLEDB.12.0,适用于Access 2007+格式。 ```mermaid graph LR A["GeoMative.cpp
创建/打开主连接"] --> B["CIOManager
导入/导出协调"] A --> C["CTdManager
TD操作"] A --> D["CProManager
项目/区域操作"] A --> E["CSptOperator
测点/脚本操作"] A --> F["CDataOperator
数据删除/更新"] B --> G["ADOX::Catalog
创建数据库/表结构"] B --> H["ADO::Connection/Command/Recordset
事务/命令/查询"] ``` 图表来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L309) - [IOManager.h](file://h/IOManager.h#L15-L51) - [msado15.tlh](file://Release/msado15.tlh#L3990-L4029) 章节来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L309) - [IOManager.h](file://h/IOManager.h#L15-L51) ## 性能考量 - 连接池策略: - 当前采用单主连接共享模式,未使用显式连接池。对于高并发写入,建议: - 将只读查询与写入分离,减少锁竞争。 - 对热点写入操作使用后台线程串行化,避免UI阻塞。 - 锁与并发: - 已设置Jet OLEDB最大锁数,有助于提升并发写入稳定性。 - 超时与隔离: - 合理设置CommandTimeout与ConnectionTimeout,避免长时间阻塞。 - 隔离级别可根据业务需求调整(默认即可满足多数场景)。 - I/O优化: - 批量写入优先使用参数化命令与事务,减少往返次数。 - 导出时一次性创建表结构,避免多次DDL变更。 [本节为通用指导,无需列出具体文件来源] ## 故障排查指南 - 常见问题与定位: - 连接失败:检查连接字符串、提供程序版本与数据库密码;查看错误描述与错误码。 - 导入失败:确认外部数据库包含版本表;异常时Rollback并清理临时文件。 - 导出失败:确认目录权限与磁盘空间;失败时删除临时文件并提示用户。 - 排查步骤: - 捕获_com_error,输出ErrorMessage与Description,结合日志定位。 - 校验连接状态(State)与错误集合(Errors)。 - 对长时间运行的事务,适当提高CommandTimeout并分批提交。 章节来源 - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L293-L310) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L101-L204) - [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1392-L1448) ## 结论 CIOManager通过主连接与目录对象实现了对Access数据库的高效导入/导出管理,配合事务与命令对象,确保了数据一致性与性能。应用程序入口负责连接的创建与打开,并在业务层共享该连接。尽管当前未实现显式连接池与严格的多线程同步,但通过合理的事务控制、参数化命令与资源释放策略,已能满足大多数业务场景。建议在后续版本中完善连接超时设置、引入线程同步与连接池策略,并在应用退出时显式关闭主连接,进一步提升稳定性与安全性。