本文讲述了旗舰版产品中,因仓库基础资料字段上的元数据配置不当,在仓库有大量仓位时会导致内存溢出问题。11月产品迭代后,将取消元数据仓库字段对仓位字段的引用。对于二次开发程序,如直接获取仓库下所有仓位将出现异常,需按仓库id重新查询。
【背景】
经检查,旗舰版存在“仓库“基础资料字段的单据、物料库存信息等元数据上,此前勾选了“仓库下的单据体“仓位”作为引用属性时,如客户业务环境上存在一个仓库大量仓位的场景(比如:一个仓库配置有5000+的仓位数据)。如下图所示
由于仓库这个基础资料的结构特殊性,仓库下一个子单据体的结构用于配置存储对应的仓位信息,对仓库赋值时,操作平台底层会创建一个动态对象实体,该基础资料实体的创建过程中同步设置引用属性的值,仓位引用属性是一个单据体,同步创建了该仓库下的仓位动态对象。平台创建单据动态实体对象大小,取决于单据对象本身分录数据量,以及其元数据上设置的基础资料引用属性,在这个配置下,该单据实质上变成了一张“单据-单据分录-单据分录下仓位”的多层分录结构大对象。分录行数虽只有3500行,但仓位对象达到了3500*9000。在单据分录较多时,易造成内存溢出,引发OOM问题。
11月份产品版本迭代后,为避免这一问题,标准产品将取消元数据仓库字段上对仓位字段的引用属性的勾选。
【二开影响】
如果现场二开程序中,存在直接通过单据、物料上的仓库对象获取其仓库下的所有仓位的方式,如下所示:
DynamicObjectCollection locations = warehouse.getDynamicObjectCollection("entryentity");
如果二开程序的仓库对象warehouse是从单据对象上直接得到(仓库动态对象是从数据库、基础资料缓存中获取的完整对象则没有问题),取消元数据引用属性后此行代码 将提示找不到entryentity属性的异常中断。
修改方式:
如果二开程序存在上面情况,应修改,如果需要获取warehouse下的所有仓位,应重新根据仓库id查询:
(1) 如现场一个仓库下仓位确保不会很多(不超过100),可以根据BusinessDataServiceHelper等方法查询得到warehouse对象,如
BusinessDataServiceHelper.loadFromCache("bd_warehouse", selectProperties, qFilter);
(2) 如现场一个仓库下仓位较多,查询仓库下所有仓位的方式应注意避免查询过多内容,仅查询出仓位id即可,如下参考为批量获取多个仓库下所属仓位id的参考(返回的结果result是key为仓库id,value为仓位id集合的Map对象):
Map<Long,Set<Long>> result = new HashMap<>(); try(DataSet locDataSet = QueryServiceHelper.queryDataSet(WarehouseLocationHelper.class.getName(), "bd_warehouse", "id, entryentity.location as locid", qFilter.toArray(), null)){ for(Row row : locDataSet) { Long locid = row.getLong("locid"); if(!locid.equals(0L)) { Long warehouseid = row.getLong("id"); Set<Long> locids = result.getOrDefault(warehouseid, new HashSet<>()); locids.add(locid); if(!result.containsKey(warehouseid)) { result.put(warehouseid, locids); } } } } return result;
推荐阅读