diff --git a/config/upstream_mirrors.php b/config/upstream_mirrors.php index 902e2c44..f759b684 100644 --- a/config/upstream_mirrors.php +++ b/config/upstream_mirrors.php @@ -408,6 +408,8 @@ return [ 'watermark' => 'updatedAt', 'batch_size' => 2000, 'max_batches_per_run' => 4, + // 160 多个 nvarchar 列,整行按 VARCHAR 建表会超过 InnoDB 行长度上限。 + 'wide_strings' => true, 'indexes' => [ ['undefined8', 'undefined7'], ['undefined2'], diff --git a/modules/EcommerceFinance/Repositories/GoodsProfitAfsRepository.php b/modules/EcommerceFinance/Repositories/GoodsProfitAfsRepository.php index 2c22b8e4..19322e25 100644 --- a/modules/EcommerceFinance/Repositories/GoodsProfitAfsRepository.php +++ b/modules/EcommerceFinance/Repositories/GoodsProfitAfsRepository.php @@ -30,12 +30,23 @@ class GoodsProfitAfsRepository try { return Schema::connection($this->connectionName())->hasTable(self::MAIN_TABLE) && Schema::connection($this->connectionName())->hasTable(self::SCHEMA_TABLE) + && $this->initialSyncCompleted() && $this->connection()->table(self::MAIN_TABLE)->exists(); } catch (\Throwable) { return false; } } + /** 首次全量同步完成前不对外使用,避免页面读到不完整的数据。 */ + private function initialSyncCompleted(): bool + { + $state = $this->connection()->table('business_mirror_table_states') + ->where('dataset_key', self::MAIN_DATASET) + ->first(['initial_completed_at']); + + return $state !== null && $state->initial_completed_at !== null; + } + /** * 页面字段键 => 上游列名(undefinedN)。 * diff --git a/modules/EcommerceFinance/Services/BusinessMirrorSchemaManager.php b/modules/EcommerceFinance/Services/BusinessMirrorSchemaManager.php index 8d4c71e7..533f3c3d 100644 --- a/modules/EcommerceFinance/Services/BusinessMirrorSchemaManager.php +++ b/modules/EcommerceFinance/Services/BusinessMirrorSchemaManager.php @@ -139,6 +139,13 @@ class BusinessMirrorSchemaManager $length = (int) ($column['max_length'] ?? 0); $precision = min(max((int) ($column['numeric_precision'] ?? 20), 1), 65); $scale = min(max((int) ($column['numeric_scale'] ?? 0), 0), min($precision, 30)); + // 超宽表(例如商品利润 160 多个 nvarchar 列)即使每列只有 50 字符, + // 全部按 VARCHAR 建表也会超过 InnoDB 行长度上限;这类数据集把非键列存为 TEXT。 + $wideStrings = (bool) app(BusinessMirrorDatasetRegistry::class) + ->definitionValue($dataset->key(), 'wide_strings', false); + $requiredInline = in_array(strtolower($name), array_map('strtolower', $dataset->keyColumns()), true) + || strcasecmp((string) $dataset->watermarkColumn(), $name) === 0 + || $this->isConfiguredIndexColumn($dataset, $name); $definition = match ($type) { 'bit', 'boolean' => $table->boolean($name), @@ -160,6 +167,7 @@ class BusinessMirrorSchemaManager // may opt a bounded legacy identifier into VARCHAR; every other // wide string remains TEXT and is stored off-page. 'char', 'nchar', 'varchar', 'nvarchar', 'character', 'character varying' => $length > 0 + && ! ($wideStrings && ! $requiredInline) && ($length <= 64 || ($length <= 255 && $this->isConfiguredIndexColumn($dataset, $name))) ? $table->string($name, $length) : $table->longText($name),