SaltController.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <?php
  2. namespace console\controllers;
  3. use bizGhs\order\models\Order as GhsOrder;
  4. use bizHd\purchase\models\Purchase;
  5. use common\components\stringUtil;
  6. use Yii;
  7. use yii\console\Controller;
  8. use yii\console\ExitCode;
  9. /**
  10. * 补充历史订单 salt 字段
  11. *
  12. * 用法:
  13. * php yii salt/fill
  14. * php yii salt/fill --dryRun=1
  15. * php yii salt/fill --batchSize=50 --sleepMs=200
  16. * php yii salt/fill-ghs-order
  17. * php yii salt/fill-cg
  18. */
  19. class SaltController extends Controller
  20. {
  21. /** @var int 每批处理条数 */
  22. public $batchSize = 100;
  23. /** @var int 每批之间的休眠毫秒数,降低白天执行时的数据库压力 */
  24. public $sleepMs = 100;
  25. /** @var int 最多处理条数,0 表示全部 */
  26. public $limit = 0;
  27. /** @var int 是否仅预览,1=是 */
  28. public $dryRun = 0;
  29. public function options($actionID)
  30. {
  31. return array_merge(parent::options($actionID), ['batchSize', 'sleepMs', 'limit', 'dryRun']);
  32. }
  33. /**
  34. * 补充 xhGhsOrder、xhCg 历史数据的 salt 字段
  35. */
  36. public function actionFill()
  37. {
  38. return $this->runFill([
  39. 'xhGhsOrder' => GhsOrder::tableName(),
  40. 'xhCg' => Purchase::tableName(),
  41. ]);
  42. }
  43. /**
  44. * 仅补充 xhGhsOrder
  45. */
  46. public function actionFillGhsOrder()
  47. {
  48. return $this->runFill([
  49. 'xhGhsOrder' => GhsOrder::tableName(),
  50. ]);
  51. }
  52. /**
  53. * 仅补充 xhCg
  54. */
  55. public function actionFillCg()
  56. {
  57. return $this->runFill([
  58. 'xhCg' => Purchase::tableName(),
  59. ]);
  60. }
  61. private function runFill(array $tables)
  62. {
  63. ini_set('memory_limit', '512M');
  64. set_time_limit(0);
  65. if ($this->batchSize < 1) {
  66. $this->stderr("batchSize 必须大于 0\n");
  67. return ExitCode::UNSPECIFIED_ERROR;
  68. }
  69. $exitCode = ExitCode::OK;
  70. foreach ($tables as $label => $tableName) {
  71. $code = $this->fillTable($label, $tableName);
  72. if ($code !== ExitCode::OK) {
  73. $exitCode = $code;
  74. }
  75. }
  76. return $exitCode;
  77. }
  78. private function fillTable($label, $tableName)
  79. {
  80. $db = Yii::$app->db;
  81. $remaining = (int)$db->createCommand(
  82. "SELECT COUNT(*) FROM {$tableName} WHERE salt = ''"
  83. )->queryScalar();
  84. $this->stdout("{$label}({$tableName}) 待补充: {$remaining}\n");
  85. if ($remaining === 0) {
  86. return ExitCode::OK;
  87. }
  88. $processed = 0;
  89. $maxProcess = $this->limit > 0 ? min($this->limit, $remaining) : $remaining;
  90. $lastId = 0;
  91. while ($processed < $maxProcess) {
  92. $batchLimit = min($this->batchSize, $maxProcess - $processed);
  93. $rows = $db->createCommand(
  94. "SELECT id FROM {$tableName} WHERE salt = '' AND id > :lastId ORDER BY id ASC LIMIT {$batchLimit}"
  95. )->bindValue(':lastId', $lastId)->queryColumn();
  96. if (empty($rows)) {
  97. break;
  98. }
  99. foreach ($rows as $id) {
  100. $id = (int)$id;
  101. $lastId = $id;
  102. if ($this->dryRun) {
  103. $this->stdout("[dry-run] {$label} id={$id}\n");
  104. $processed++;
  105. continue;
  106. }
  107. $salt = stringUtil::charsShuffleLowerCase(10);
  108. $affected = $db->createCommand(
  109. "UPDATE {$tableName} SET salt = :salt WHERE id = :id AND salt = ''"
  110. )->bindValues([
  111. ':salt' => $salt,
  112. ':id' => $id,
  113. ])->execute();
  114. if ($affected > 0) {
  115. $processed++;
  116. }
  117. }
  118. $this->stdout("{$label} 已处理 {$processed}/{$maxProcess}\n");
  119. if ($this->sleepMs > 0 && $processed < $maxProcess) {
  120. usleep($this->sleepMs * 1000);
  121. }
  122. }
  123. $left = (int)$db->createCommand(
  124. "SELECT COUNT(*) FROM {$tableName} WHERE salt = ''"
  125. )->queryScalar();
  126. $this->stdout("{$label} 完成,本次处理 {$processed} 条,剩余 {$left} 条\n");
  127. return ExitCode::OK;
  128. }
  129. }