Magento 2.4.2大批量产品导出时最终价格字段缺失问题咨询
Magento 2.4.2 大批量产品导出最终价格缺失问题排查与修复
问题触发原因
- 代码逻辑bug:循环判断条件错误,
$additionalColumns是导出字段数组,原代码直接用整数$i和数组比较大小,PHP中数组与整数比较时数组恒为更大值,导致循环永远不会执行,字段映射逻辑失效,最终价格写入的字段名和CSV表头不匹配,显示为空。 - 内存溢出/进程中断:40万条数据场景下,循环内每次调用
ProductRepository::get()全量加载产品模型,单条产品模型加载就会占用数百KB内存,同时触发大量关联数据加载、插件执行,很快会超过PHP内存上限,进程被系统强制kill后,后续所有产品的最终价格都不会被写入。 - 异常未捕获:代码仅声明抛出
NoSuchEntityException,未做异常捕获处理,一旦遇到SKU不存在、多店铺场景下产品未分配到对应店铺、价格计算逻辑异常等情况,会直接中断整个导出流程,导致后续所有数据的价格字段缺失。 - 多店铺适配问题:
ProductRepository::get()默认传入当前店铺ID,若导出任务指定了其他店铺,会查询到错误的价格,甚至返回空值。 - 数据库性能瓶颈:单条查询价格的方式在40万条数据的场景下会产生40万次数据库查询,极易触发数据库超时、连接数占满等问题,导致查询失败价格为空。
修复方案
核心优化点
- 修复循环逻辑bug,将循环判断条件改为数组长度
- 替换全量产品模型加载逻辑,改为直接从价格索引表批量查询对应SKU的最终价格,避免单条查询开销
- 增加异常捕获逻辑,单条产品价格查询失败不中断整体导出
- 适配导出任务的店铺ID,正确查询对应店铺的最终价格
- 批量处理每批导出数据,单次查询整批产品的所有价格,减少数据库查询次数
优化后代码示例
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory; use Firebear\ImportExport\Model\Export\Product as FirebearProduct; class AfterGetExportDataPlugin { public const FINAL_PRICE_EXPORT = 'export_finalPrice'; private ProductCollectionFactory $productCollectionFactory; public function __construct( ProductCollectionFactory $productCollectionFactory ) { $this->productCollectionFactory = $productCollectionFactory; } /** * @param FirebearProduct $subject * @param array $result * @return array */ public function afterGetExportData(FirebearProduct $subject, array $result): array { // 判断是否需要导出最终价格 $additionalColumns = $subject->getParameters()['list'] ?? []; if (!in_array(self::FINAL_PRICE_EXPORT, $additionalColumns, true)) { return $result; } // 修复循环条件bug,获取字段映射别名 $exportAttributeMapping = self::FINAL_PRICE_EXPORT; $columnsCount = count($additionalColumns); for ($i = 0; $i < $columnsCount; $i++) { if (($additionalColumns[$i] ?? '') === self::FINAL_PRICE_EXPORT) { $exportAttributeMapping = $subject->getParameters()['replace_code'][$i] ?? self::FINAL_PRICE_EXPORT; break; } } try { // 批量获取当前批次所有SKU的最终价格 $skuList = array_column($result, 'sku'); $storeId = $subject->getParameters()['store_id'] ?? 0; $productCollection = $this->productCollectionFactory->create(); $productCollection->addAttributeToSelect('sku') ->addPriceData() ->addStoreFilter($storeId) ->addFieldToFilter('sku', ['in' => $skuList]); $priceMap = []; foreach ($productCollection as $product) { $priceMap[$product->getSku()] = (float)$product->getFinalPrice(); } // 批量赋值 foreach ($result as &$product) { $product[$exportAttributeMapping] = $priceMap[$product['sku']] ?? 0.00; } } catch (\Exception $e) { // 异常不中断导出,可自行添加日志记录错误 foreach ($result as &$product) { $product[$exportAttributeMapping] = 0.00; } } return $result; } }
内容的提问来源于stack exchange,提问作者user14141548
相关产品推荐
相关产品推荐

