简体   繁体   English

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

[英]Strange behavior in PHP + MySQL (Yii2)

I need your help and advice.我需要你的帮助和建议。

I have a program that show information about users.我有一个显示用户信息的程序。 Every an hour system (based Yii2) takes infromation from external system by SOAP protocol.每小时系统(基于 Yii2)通过 SOAP 协议从外部系统获取信息。 Response constists over 8000 rows, that why i chunked response by 1000 rows and repeat request until get all rows (execution time near 30-45 seconds).响应包含超过 8000 行,这就是为什么我将响应分成 1000 行并重复请求直到获得所有行(执行时间接近 30-45 秒)。 Each response i store in table user_temp (MySQL) by batchInsert method (Yii2).我通过batchInsert方法(Yii2)存储在表user_temp (MySQL)中的每个响应。 Before storing i truncate table user_temp .在存储之前,我会截断表user_temp After save data, i truncate data from main table user and insert from temporary table user_temp by query保存数据后,我从主表user截断数据并通过查询从临时表user_temp插入

INSERT INTO user SELECT * FROM user_temp

Sometimes query is success, but often is fail with error:有时查询是成功的,但经常是失败并出现错误:
'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry \\'1\\' for key \\'PRIMARY\\' The SQL being executed was: INSERT INTO user SELECT * FROM user_temp' 'SQLSTATE[23000]: 完整性约束违规:1062 Duplicate entry \\'1\\' for key \\'PRIMARY\\' 正在执行的 SQL 是: INSERT INTO user SELECT * FROM user_temp'

Tables scheme for user_temp and user is same (migration) 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',
    ]);

code:代码:

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++;
    }
}

You are trying to insert data that already is in the user table.您正在尝试插入用户表中已有的数据。 As id is your primary key you are getting that error.由于 id 是您的主键,因此您会收到该错误。

If the info from the external application is leading, then its easy and you can truncate the whole table, or if you have more complex requirements, update the already existing record.如果来自外部应用程序的信息领先,那么这很容易,您可以截断整个表,或者如果您有更复杂的要求,请更新现有记录。 Thats up to your needs.这取决于您的需求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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