繁体   English   中英

PHP + MySQL (Yii2) 中的奇怪行为

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM