mysql - Laravel 参数绑定(bind)导致偶尔出现 MySQL 一般错误

标签 mysql laravel parameters

我有一个整数数组,需要作为一批行插入。每行都需要一些其他数据。

$ids = [1,2]
$thing = 1
$now = Carbon::now(); // This is just a timestamp.
$binding_values = trim(str_repeat("({$thing}, ?, '{$now}'),", count($ids)), ',');

字符串$binding_values看起来像这样:

“(1, ?, '2019-01-01 00:00:00'), (1, ?, '2019-01-01 00:00:00')”

然后我准备查询字符串并将参数绑定(bind)到它。使用 IGNORE 是因为我在表上有一个复合唯一索引。不过,它似乎与问题无关,因此我省略了详细信息。

DB::insert("
    INSERT IGNORE INTO table (thing, id, created_at)
    VALUES {$binding_values}
", $ids);

几乎一直有效,但时不时地我会收到错误SQLSTATE[HY000]:一般错误:2031

我执行此参数的方式是否与 Laravel 绑定(bind)了某种反模式?此错误的根源可能是什么?

因为该方法不存在注入(inject)风险,并且该方法不可能扩展到有注入(inject)风险的用例,所以我对其进行了修改以烘焙所有参数并跳过参数绑定(bind)。到目前为止我还没有看到任何错误。

我仍然想知道是什么可能导致此行为,以便我将来可以更好地管理它。如果您有任何见解,我将不胜感激。

最佳答案

除了将参数烘焙到查询中之外,我没有发现您的查询有什么大问题,这很容易受到 SQL 注入(inject)的影响。

据我所知,您的问题是您需要 INSERT ÌGNORE INTO,Laravel 不支持开箱即用。您是否考虑过使用像staudenmeir/laravel-upsert这样的第三方包?

另一种方法是将查询包装在事务中并首先选择现有条目,这样您就有机会不再插入它们:

$ids   = [1, 2];
$thing = 1;
$time  = now();

DB::transaction(function () use ($ids, $thing, $time) {
    $existing = DB::table('some_table')->whereIn('id', $ids)->pluck('id')->toArray();
    $toInsert = array_diff($ids, $existing);

    $dataToInsert = array_map(function ($id) use ($thing, $time) {
        return [
            'id' => $id,
            'thing' => $thing,
            'created_at' => $time
        ];
    }, $toInsert);

    DB::table('some_table')->insert($dataToInsert);
});

这样,您将只插入尚不存在的内容,但您也将保留在查询生成器的框架功能内。唯一的缺点是,由于第二次往返数据库,速度会稍微慢一些。

关于mysql - Laravel 参数绑定(bind)导致偶尔出现 MySQL 一般错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57542386/

相关文章:

php - 如何从MySQL向表中输入数据?

laravel - 如何在 laravel Blade 的图像 src 中使用 vue 变量?

sql - 如何选择最新的数据?

php - 在 laravel 5.2 中为特定路由禁用 web 中间件

haskell - 在 Haskell 中,当你只传递一个列表时,map 函数是什么意思?

php - 存在未知列的 MySQL 警告

mysql - 筛选在 mysql 中存储为 varchar 的日期

mysql - 无法在 Linux 上设置对 MySQL 服务器的远程访问

jQuery.Get,带有特殊字符的参数

parameters - Cloudformation 参数传递到模板失败