shish 2 месяцев назад
Родитель
Сommit
fb99e12fa2
1 измененных файлов с 156 добавлено и 0 удалено
  1. 156 0
      console/controllers/SaltController.php

+ 156 - 0
console/controllers/SaltController.php

@@ -0,0 +1,156 @@
+<?php
+
+namespace console\controllers;
+
+use bizGhs\order\models\Order as GhsOrder;
+use bizHd\purchase\models\Purchase;
+use common\components\stringUtil;
+use Yii;
+use yii\console\Controller;
+use yii\console\ExitCode;
+
+/**
+ * 补充历史订单 salt 字段
+ *
+ * 用法:
+ *   php yii salt/fill
+ *   php yii salt/fill --dryRun=1
+ *   php yii salt/fill --batchSize=50 --sleepMs=200
+ *   php yii salt/fill-ghs-order
+ *   php yii salt/fill-cg
+ */
+class SaltController extends Controller
+{
+    /** @var int 每批处理条数 */
+    public $batchSize = 100;
+
+    /** @var int 每批之间的休眠毫秒数,降低白天执行时的数据库压力 */
+    public $sleepMs = 100;
+
+    /** @var int 最多处理条数,0 表示全部 */
+    public $limit = 0;
+
+    /** @var int 是否仅预览,1=是 */
+    public $dryRun = 0;
+
+    public function options($actionID)
+    {
+        return array_merge(parent::options($actionID), ['batchSize', 'sleepMs', 'limit', 'dryRun']);
+    }
+
+    /**
+     * 补充 xhGhsOrder、xhCg 历史数据的 salt 字段
+     */
+    public function actionFill()
+    {
+        return $this->runFill([
+            'xhGhsOrder' => GhsOrder::tableName(),
+            'xhCg' => Purchase::tableName(),
+        ]);
+    }
+
+    /**
+     * 仅补充 xhGhsOrder
+     */
+    public function actionFillGhsOrder()
+    {
+        return $this->runFill([
+            'xhGhsOrder' => GhsOrder::tableName(),
+        ]);
+    }
+
+    /**
+     * 仅补充 xhCg
+     */
+    public function actionFillCg()
+    {
+        return $this->runFill([
+            'xhCg' => Purchase::tableName(),
+        ]);
+    }
+
+    private function runFill(array $tables)
+    {
+        ini_set('memory_limit', '512M');
+        set_time_limit(0);
+
+        if ($this->batchSize < 1) {
+            $this->stderr("batchSize 必须大于 0\n");
+            return ExitCode::UNSPECIFIED_ERROR;
+        }
+
+        $exitCode = ExitCode::OK;
+        foreach ($tables as $label => $tableName) {
+            $code = $this->fillTable($label, $tableName);
+            if ($code !== ExitCode::OK) {
+                $exitCode = $code;
+            }
+        }
+
+        return $exitCode;
+    }
+
+    private function fillTable($label, $tableName)
+    {
+        $db = Yii::$app->db;
+        $remaining = (int)$db->createCommand(
+            "SELECT COUNT(*) FROM {$tableName} WHERE salt = ''"
+        )->queryScalar();
+
+        $this->stdout("{$label}({$tableName}) 待补充: {$remaining}\n");
+        if ($remaining === 0) {
+            return ExitCode::OK;
+        }
+
+        $processed = 0;
+        $maxProcess = $this->limit > 0 ? min($this->limit, $remaining) : $remaining;
+        $lastId = 0;
+
+        while ($processed < $maxProcess) {
+            $batchLimit = min($this->batchSize, $maxProcess - $processed);
+            $rows = $db->createCommand(
+                "SELECT id FROM {$tableName} WHERE salt = '' AND id > :lastId ORDER BY id ASC LIMIT {$batchLimit}"
+            )->bindValue(':lastId', $lastId)->queryColumn();
+
+            if (empty($rows)) {
+                break;
+            }
+
+            foreach ($rows as $id) {
+                $id = (int)$id;
+                $lastId = $id;
+
+                if ($this->dryRun) {
+                    $this->stdout("[dry-run] {$label} id={$id}\n");
+                    $processed++;
+                    continue;
+                }
+
+                $salt = stringUtil::charsShuffleLowerCase(10);
+                $affected = $db->createCommand(
+                    "UPDATE {$tableName} SET salt = :salt WHERE id = :id AND salt = ''"
+                )->bindValues([
+                    ':salt' => $salt,
+                    ':id' => $id,
+                ])->execute();
+
+                if ($affected > 0) {
+                    $processed++;
+                }
+            }
+
+            $this->stdout("{$label} 已处理 {$processed}/{$maxProcess}\n");
+
+            if ($this->sleepMs > 0 && $processed < $maxProcess) {
+                usleep($this->sleepMs * 1000);
+            }
+        }
+
+        $left = (int)$db->createCommand(
+            "SELECT COUNT(*) FROM {$tableName} WHERE salt = ''"
+        )->queryScalar();
+        $this->stdout("{$label} 完成,本次处理 {$processed} 条,剩余 {$left} 条\n");
+
+        return ExitCode::OK;
+    }
+}