【问题标题】:Yii2 Insert Ignore / Insert duplicatesYii2 插入忽略/插入重复项
【发布时间】:2015-01-30 15:44:43
【问题描述】:

我对 Yii2 比较陌生,到目前为止我非常喜欢它。 然而,我发现一个与数据库插入相关的问题,更具体地说是 MySQL。

问题很简单:我正在向表中插入值,并且需要检查重复项,所以我的想法是使用 INSERT IGNOREON DUPLICATE KEY UPDATE强>.

这是我用于插入的代码:

$db->createCommand()
->insert('sdg_fb_apps', [
'fb_id' => $app->id,
'page_id' => $page_id,
'name' => $app->name,
'app_id' => $app_id,
'app_name' => $app_name,
])
->execute();

我必须唯一的键:id 和 app_id,如果我运行这段代码,我显然会被 Yii 抛出一个异常。

有这个扩展,但据我了解仅适用于 Yii 1.0:http://www.yiiframework.com/extension/rdbcommand

我还在GitHub 上发现了这个代码 sn-p,看起来像这样:

class MyQueryBuilder extends yii\db\mysql\QueryBuilder
{
    public function batchInsert($table, $columns, $rows)
    {
        $sql = parent::batchInsert($table, $columns, $rows);
        $sql .= 'ON DUPLICATE KEY UPDATE';
        return $sql;
    }
}

我不明白如何扩展 Querybuilder,可以通过组件吗?

我通过查询来查看 app_id 之前是否已经在数据库中,然后仅在它们不存在时才插入,从而实现了我正在寻找的东西,但是这应该必须扩展到巨大的数字和这种方法可能不是最好的。

任何指导将不胜感激,在此先感谢。

【问题讨论】:

    标签: php mysql yii2


    【解决方案1】:

    从 Yii 2.0.14 开始有一个 upsert() 方法可以用于此。

    $db->createCommand()
        ->upsert(
            'sdg_fb_apps',
            [
                'fb_id' => $app->id,
                'page_id' => $page_id,
                'name' => $app->name,
                'app_id' => $app_id,
                'app_name' => $app_name,
            ],
            false
        )
        ->execute();
    

    【讨论】:

      【解决方案2】:

      你的问题的关键是方法$db->createCommand()。在内部,它使用默认为 yii\db\Command$commandClass 公共属性。您可以在您的应用配置中更改它以覆盖 batchInsert() 等命令方法。以下是我的应用程序的示例:

      'db' => [
          'class' => 'yii\db\Connection',
          'charset' => 'utf8',
          'enableSchemaCache' => YII_ENV_PROD,
          'commandClass' => 'app\db\MyCommand'
      ],
      

      您的命令类可能如下所示:

      class MyCommand extends yii\db\Command
      {
          public function batchInsert($table, $columns, $rows)
          {
              parent::batchInsert($table, $columns, $rows);
              $sql = $this->getRawSql();
              $sql .= ' ON DUPLICATE KEY UPDATE';
              $this->setRawSql($sql);
      
              return $this;
          }
      }
      

      但我宁愿引入单独的方法,例如batchInsertUpdate() 什么的。

      【讨论】:

        【解决方案3】:

        一年多过去了,我在这里找到了这个悬而未决的问题。我看到这有一些吸引力,所以最好添加一个正确的答案。

        在 Yii2 中的想法是找到模型,检查是否存在,然后保存。框架会自动更新或插入,这是我从Viewlike.us - Yii2 Insert and Ignore duplicates得到的一个sn-p:

        $model = YourModel::findOne(ID); // findOne() searches for the table key, you can use find()->where('=', 'column', 'name')->one(); to identify the model.
        
        if(!$model):
            $model = new YourModel();
        endif;
        
        $model->column_1 = 'text';
        $model->column_2 = 123; // integer
        $model->save();
        

        【讨论】:

        • 因为谁在乎比赛条件,对吧?
        【解决方案4】:

        有很多事情需要考虑,可能还有更好的方法来完成您的任务,但最直接的答案(基于您提供的信息)是扩展 QueryBuilder。

        简单地创建一个具有适当命名空间的应用程序组件,并如上所示扩展 QueryBuilder。

        如果您对表使用 ActiveRecord 模型而不是直接执行 sql 命令,那么您可以通过其他方式来实现您想要的目标。

        【讨论】:

          【解决方案5】:

          对于 Yii 1(Yii 2 应该类似)我继承了 CActiveRecord 然后我将插入函数复制到 insertIgnoreDuplicates, 我在 createInsertCommand 调用后做了以下更改:

          /**
               * Inserts ignore duplicates a row into the table based on this active record attributes.
               * If the table's primary key is auto-incremental and is null before insertion,
               * it will be populated with the actual value after insertion.
               * Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
               * After the record is inserted to DB successfully, its {@link isNewRecord} property will be set false,
               * and its {@link scenario} property will be set to be 'update'.
               * @param array $attributes list of attributes that need to be saved. Defaults to null,
               * meaning all attributes that are loaded from DB will be saved.
               * @return boolean whether the attributes are valid and the record is inserted successfully.
               * @throws CDbException if the record is not new
               */
              public function insertIgnoreDuplicates($attributes = null)
              {
                  try {
                      return $this->insert($attributes);
                  } catch (CDbException $ex) {
                      if ($ex->code == 23000) // ignore duplicated key 
                      {
                      } else {
                          throw $ex;
                      }
                  }
              }
          

          用法:

          $x = new record();
          $x->attr1  = 'val';
          $x->insertIgnoreDuplicates();
          

          【讨论】:

            猜你喜欢
            • 2016-10-22
            • 1970-01-01
            • 2020-01-03
            • 2023-03-13
            • 1970-01-01
            • 1970-01-01
            • 2012-08-25
            • 2016-03-03
            相关资源
            最近更新 更多