对象缓存机制是SunvStation地理编辑系统的核心组件,用于在批量创建和修改地理对象时提供高效的内存管理。该机制通过在内存中暂存对象,避免频繁的数据库I/O操作,显著提升大批量数据处理的性能。缓存机制区分了新建对象和修改对象两种场景,分别采用不同的缓存策略,并通过统一的事务性接口完成数据库持久化。 Sources: [PySSProcess.py](PySSProcess.py#L26-L46) ## 缓存架构概述 对象缓存机制采用多层次的缓存架构,通过SSProcessManager类的成员变量管理不同类型的缓存。缓存系统分为三大类别:新建对象缓存、修改对象缓存和删除对象缓存,每种类别又进一步区分为地物对象和注记对象。 ```mermaid classDiagram class SSProcessManager { +GeoBaseList bufferObjList +GeoBaseList bufferNoteList +list newBufferObjList +list newBufferNoteList +tuple curNewObj +GeoBaseList delBufferGeoList +createNewObjByCode(code) +setNewObjValue(field, value) +addNewObjPoint(x, y, z, type, name) +addNewObjToSaveObjList() +saveBufferObjToDatabase() } class GeoEditMixin { <> +transMemoDataToExtendAttr(geoList) +persistTempGeoList(geoVec) +persistTempNoteList(noteVec) } class GeoBaseList { +append(geo) +empty() +clear() } class GeoBase { +getObjectType() +getCode() +setMemoData(fields, values) +getDatasetName() } SSProcessManager *-- GeoBaseList : 管理缓存列表 SSProcessManager *-- GeoBase : 封装几何对象 SSProcessManager --> GeoEditMixin : 继承缓存操作 GeoBaseList o-- GeoBase : 包含对象 ``` 该架构体现了**关注点分离**的设计原则:SSProcessManager负责缓存容器管理,GeoEditMixin提供缓存操作的具体实现,GeoBase和GeoBaseList作为数据载体。缓存对象以pair形式存储,其中第一个元素是GeoObject实例(包含数据集引用和唯一ID),第二个元素是具体的几何对象(PointObject、LineObject、AreaObject或MarkNote)。 Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L28-L54) ## 缓存类型与分类 缓存机制根据对象状态和类型进行明确分类,这种设计使得系统能够对不同场景采用优化的处理策略。 ### 按操作状态分类 | 缓存类型 | 存储容器 | 对象来源 | 持久化方式 | 典型应用场景 | |---------|---------|---------|-----------|------------| | 新建对象缓存 | `newBufferObjList` / `newBufferNoteList` | 脚本创建的新对象 | `addGeoObject()` 添加到地图 | 批量导入数据、程序化生成地物 | | 修改对象缓存 | `bufferObjList` / `bufferNoteList` | 从地图加载并修改的对象 | `saveDatabase()` 更新数据库 | 属性批量更新、几何形状编辑 | | 删除对象缓存 | `delBufferGeoList` | 标记为删除的对象 | `delGeoBaseComponent()` 执行删除 | 清理过期数据、对象合并操作 | | 当前新建对象 | `curNewObj` | 正在创建过程中的临时对象 | 转移至其他缓存或丢弃 | 交互式创建、参数化建模 | ### 按对象类型分类 地物对象和注记对象的物理存储位置不同,系统通过`getObjectType()`方法进行类型识别(e_Point_Obj=0、e_Line_Obj=1、e_Area_Obj=2、e_Note_Obj=3),并自动路由到相应的缓存容器中。 Sources: [PySSProcess.py](PySSProcess.py#L32-L40) ## 缓存生命周期管理 对象的生命周期在缓存系统中遵循明确的阶段划分,从对象创建开始,经过属性设置和几何编辑,最终通过事务性接口持久化到数据库。 ```mermaid flowchart LR A[开始创建对象] --> B{创建方式} B -->|通过编码创建| C[createNewObjByCode] B -->|通过注记类创建| D[createNewObjByClass] B -->|默认类型创建| E[createDefaultGeoBase] C --> F[curNewObj 临时缓存] D --> F E --> F F --> G[setNewObjValue 设置属性] G --> H[addNewObjPoint 添加坐标点] H --> I{下一步操作} I -->|加入选择集| J[addNewObjToSelObjList] I -->|加入保存列表| K[addNewObjToSaveObjList] I -->|放弃创建| L[deleteNewObj] K --> M[newBufferObjList/newBufferNoteList] J --> N[selGeoList/selNoteList] M --> O[saveBufferObjToDatabase 批量保存] N --> O O --> P[transMemoDataToExtendAttr 属性转换] P --> Q[map.addGeoObject 添加到地图] Q --> R[map.saveDatabase 写入数据库] R --> S[清除缓存列表] ``` 该生命周期体现了**延迟加载**和**批量处理**的优化策略:对象在内存中完成所有编辑操作,仅在最后阶段才与数据库交互,显著减少了网络往返和数据锁争用。 Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L120-L210) ## 核心API详解 ### 对象创建API `createNewObjByCode()` 是新建对象的主要入口,通过编码获取地物定义并创建相应类型的几何对象。该方法会自动从当前数据源获取特征定义,包括对象类型、颜色、线型、线宽等属性,并应用到新创建的对象上。 ```python # 通过编码创建新地物对象 obj, geo = SSProcess.createNewObjByCode(3103013) if obj is not None: # 设置对象属性 SSProcess.setNewObjValue("SSObj_Name", "新建道路") SSProcess.setNewObjValue("[宽度]", "15.5") # 添加坐标点(线对象) SSProcess.addNewObjPoint(100.0, 200.0, 0.0, 0, "") SSProcess.addNewObjPoint(150.0, 250.0, 0.0, 0, "") # 将对象加入保存列表 SSProcess.addNewObjToSaveObjList() ``` Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L133-L163) ### 属性设置API `setNewObjValue()` 方法支持基本属性和扩展属性的统一设置。基本属性以`SSObj_`前缀标识,扩展属性使用方括号`[]`包裹。该方法还支持批量设置多个扩展属性,通过逗号分隔属性名和值。 **属性设置对比表:** | 属性类型 | 语法格式 | 存储位置 | 转换逻辑 | |---------|---------|---------|---------| | 基本属性 | `SSObj_Name` | 对象内置字段 | 直接映射到GeoBase的getter/setter | | 单个扩展属性 | `[自定义字段名]` | MemoData字段 | 通过StringArray键值对存储 | | 批量扩展属性 | `[字段1],[字段2]` | MemoData字段 | 解析后分别设置键值对 | Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L193-L260) ### 批量持久化API `saveBufferObjToDatabase()` 是缓存机制的核心事务接口,负责将所有缓存中的对象持久化到数据库。该方法按数据集分组处理对象,先调用`addGeoObject()`添加新对象,再通过`transMemoDataToExtendAttr()`将MemoData转换为扩展属性,最后调用`saveDatabase()`提交修改。 ```mermaid sequenceDiagram participant API as saveBufferObjToDatabase() participant Cache as 缓存列表 participant Map as ScaleMap participant DB as 数据库 API->>Cache: 读取newBufferObjList/newBufferNoteList API->>API: 按数据集分组 loop 每个数据集分组 API->>Map: addGeoObject(geoList) API->>Map: setExtentAttr(geo, fields, values) end API->>Cache: 清空newBufferObjList/newBufferNoteList API->>Cache: 读取bufferObjList/bufferNoteList API->>Map: setExtentAttr(geo, fields, values) API->>Map: saveDatabase(geoList) API->>Cache: 清空bufferObjList/bufferNoteList API->>Map: delGeoBaseComponent(delBufferGeoList) API->>Cache: 清空delBufferGeoList ``` 该方法实现了**原子性**的事务特性:所有缓存对象的保存操作作为一个整体提交,成功则全部生效,失败则回滚至保存前状态。同时,通过数据集分组优化了数据库锁粒度,提高了并发性能。 Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L475-L508) ### 备忘数据转换API `transMemoDataToExtendAttr()` 方法负责将对象的备忘数据(MemoData)转换为扩展属性。这是必要的中间步骤,因为MemoData是Python层面的临时存储格式,而扩展属性是数据库层面的持久化格式。 转换过程在事务边界内进行(`beginSetExtentAttr()` / `endSetExtentAttr()`),确保扩展属性设置的原子性。对于具有大量扩展属性的对象,该操作可能产生显著的性能开销,建议批量处理时控制对象数量。 Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L464-L473) ## 缓存与选择集的关系 缓存列表与选择集是两个独立但相关的容器系统。选择集(`selGeoList`、`selNoteList`)用于对象的逻辑分组和查询,而缓存列表(`bufferObjList`、`newBufferObjList`等)用于对象的事务性持久化。 **关系对比表:** | 容器类型 | 主要用途 | 数据来源 | 是否持久化 | 清除时机 | |---------|---------|---------|-----------|---------| | 选择集 | 逻辑分组、批量查询 | 从地图加载或新建对象添加 | 否 | clearSelection()手动清除 | | 新建对象缓存 | 事务性保存新对象 | 通过createNewObjByCode创建 | 是 | saveBufferObjToDatabase()自动清除 | | 修改对象缓存 | 事务性更新现有对象 | 从选择集加载并修改 | 是 | saveBufferObjToDatabase()自动清除 | | 删除对象缓存 | 事务性删除对象 | 标记为删除的对象 | 是 | saveBufferObjToDatabase()自动清除 | `addNewObjToSelObjList()` 和 `addNewObjToSaveObjList()` 方法体现了这种分离设计:前者将对象加入选择集进行后续查询或操作,后者将对象加入缓存列表准备持久化。一个对象可以同时存在于两个容器中,也可以仅存在于其中一个。 Sources: [ssprocess_mixins/geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L415-L430) ## 最佳实践与注意事项 ### 批量操作的性能优化 对于大量对象的批量操作,建议遵循以下最佳实践: 1. **避免频繁调用saveBufferObjToDatabase()**:该方法会触发数据库事务,每次调用都有固定开销。应累积足够多的对象后再批量保存,建议每1000-5000个对象保存一次。 2. **合理使用数据集分组**:虽然`saveBufferObjToDatabase()`内部已实现数据集分组,但在创建对象时尽量按数据集顺序添加对象,可以减少分组操作的复杂度。 3. **控制扩展属性数量**:每个对象的扩展属性存储在MemoData中,过多扩展属性会增加内存占用和序列化开销。建议将高频查询的属性映射为基本属性,低频属性作为扩展属性。 ### 内存管理注意事项 缓存对象在Python层面持有C++对象的引用,可能导致内存泄漏。以下场景需要特别关注: - **对象创建后未加入保存列表**:如果调用了`createNewObjByCode()`但未调用`addNewObjToSaveObjList()`或`addNewObjToSelObjList()`,对象会一直保留在`curNewObj`中,占用内存直到下一次创建操作覆盖。 - **事务中断后的缓存清理**:如果在调用`saveBufferObjToDatabase()`之前发生异常,缓存列表中的对象不会被自动清理。建议在异常处理中手动调用缓存清除操作或重新创建SSProcess实例。 ### 并发安全注意事项 缓存机制不是线程安全的。如果在多线程环境下使用,需要通过外部同步机制(如线程锁)确保对SSProcess实例的访问序列化。系统设计的典型使用场景是单线程的脚本执行环境。 ### 与撤销系统的集成 缓存机制与[撤销标记管理](25-che-xiao-biao-ji-guan-li)功能存在交互。如果需要在保存到数据库前支持撤销操作,应将对象同时添加到选择集和保存列表中,这样可以在不触发数据库提交的情况下回滚修改。 ## 相关主题 对象缓存机制是地理编辑功能链中的关键环节。掌握缓存机制后,建议继续学习以下相关主题: - **[批量保存到数据库](24-pi-liang-bao-cun-dao-shu-ju-ku)**:深入了解`saveBufferObjToDatabase()`方法的实现细节和性能调优策略 - **[创建默认地物对象](19-chuang-jian-mo-ren-di-wu-dui-xiang)**:学习通过不同方式创建地物对象的方法和编码映射关系 - **[地物基本属性详解](17-di-wu-ji-ben-shu-xing-xiang-jie)**:了解基本属性的完整列表和语义说明 - **[扩展属性与自定义属性](18-kuo-zhan-shu-xing-yu-zi-ding-yi-shu-xing)**:掌握扩展属性的存储机制和访问方法 - **[对象删除操作](22-shan-chu-dui-xiang-cao-zuo)**:理解删除缓存的工作原理和事务性保证