[英]Strange behavior in PHP + MySQL (Yii2)
我需要你的帮助和建议。
我有一个显示用户信息的程序。 每小时系统(基于 Yii2)通过 SOAP 协议从外部系统获取信息。 响应包含超过 8000 行,这就是为什么我将响应分成 1000 行并重复请求直到获得所有行(执行时间接近 30-45 秒)。 我通过batchInsert方法(Yii2)存储在表user_temp (MySQL)中的每个响应。 在存储之前,我会截断表user_temp 。 保存数据后,我从主表user截断数据并通过查询从临时表user_temp插入
INSERT INTO user SELECT * FROM user_temp
有时查询是成功的,但经常是失败并出现错误:
'SQLSTATE[23000]: 完整性约束违规:1062 Duplicate entry \\'1\\' for key \\'PRIMARY\\' 正在执行的 SQL 是: INSERT INTO user SELECT * FROM user_temp'
user_temp 和 user 的表方案相同(迁移)
$this->createTable('user', [
'id' => 'pk',
'object1' => Schema::TYPE_SMALLINT,
'object2' => Schema::TYPE_SMALLINT,
'object3' => Schema::TYPE_SMALLINT,
'ind_achivement' => Schema::TYPE_SMALLINT,
'type_document' => Schema::TYPE_STRING,
'is_benefit' => Schema::TYPE_SMALLINT,
'is_olymp' => Schema::TYPE_SMALLINT,
'is_target' => Schema::TYPE_SMALLINT,
'is_enrolled' => Schema::TYPE_SMALLINT,
'priority' => Schema::TYPE_SMALLINT,
'order' => Schema::TYPE_STRING,
'oop_base' => Schema::TYPE_STRING,
'is_expelled' => Schema::TYPE_SMALLINT,
'enrollee_code' => Schema::TYPE_STRING,
'enrollee_name' => Schema::TYPE_STRING,
'total_balls' => Schema::TYPE_INTEGER,
'is_concurs_out' => Schema::TYPE_SMALLINT,
'is_rec_by_priority'=> Schema::TYPE_SMALLINT,
'agreement_enroll' => Schema::TYPE_SMALLINT,
'cg_code' => Schema::TYPE_STRING,
'date_update' => Schema::TYPE_TIMESTAMP.' NOT NULL DEFAULT CURRENT_TIMESTAMP',
]);
代码:
public function actionStart($token = null)
{
if(!is_null($token) && ($token === Yii::$app->params['token'])){
try{
set_time_limit(0);
$this->countRows('user_temp');
$this->truncateTable('user_temp');
$this->countRows('user_temp');
$this->delayWithCheck('user_temp', 3);
$again = true;
$step = 1000;
$stepNumber = 1;
$config = new SoapConfig(Yii::$app->params['wsdl_url'], Yii::$app->params['wsdl_login'], Yii::$app->params['wsdl_password']);
while($again){
$sn = ($stepNumber - 1) * $step + 1;
$sl = $stepNumber * $step;
$client = new SoapClient($config, 'Rating', [
'NumberPK' => Yii::$app->params['numberPC'],
'From' => $sn,
'To' => $sl
]);
$abiturients = Util::toArray($client->getResponse()->RatingRow);
$dateTime = str_replace('T', ' ', $client->getResponse()->DateUpdate);
$count = count($abiturients);
$batchAbiturients = Util::prepareEnrolleToBatchInsert($abiturients, $dateTime);
$this->addUsers($batchAbiturients);
if($count < $step){
$again = false;
}
$stepNumber++;
unset($client);
}
$this->truncateTable('user');
$this->countRows('user');
$this->delayWithCheck('user', 3);
$this->copyTable('user_temp', 'user');
$this->countRows('user_temp');
$this->countRows('user');
}catch (\Exception $e){
VarDumper::dump($e->getMessage());
}
}else{
echo 'token not exist or invalid';
}
}
protected function truncateTable($table = null)
{
if(!$table){
throw new \BadMethodCallException("must be name for Table");
}
$db = Yii::$app->db;
$trnasaction = $db->beginTransaction();
try{
$rows = $db->createCommand('TRUNCATE TABLE '.$table)->execute();
$trnasaction->commit();
echo 'Table '.$table.' was truncated';
}catch (\Exception $e){
$trnasaction->rollBack();
throw $e;
}
}
protected function delayWithCheck($tableForCheck, $sec = 3)
{
$check = true;
$alert = 0;
while($check){
$countRows = (new Query())->from($tableForCheck)->count();
if((int)$countRows === 0){
$check = false;
}
if($alert === 10){
throw new \Exception('Long query execute from '.$tableForCheck);
}
echo '<div>Delay: '.$countRows.' iteration</div>';
sleep($sec);
$alert++;
}
}
您正在尝试插入用户表中已有的数据。 由于 id 是您的主键,因此您会收到该错误。
如果来自外部应用程序的信息领先,那么这很容易,您可以截断整个表,或者如果您有更复杂的要求,请更新现有记录。 这取决于您的需求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.