【问题标题】:Migrating PHP PDO to Laravel PDO causes Invalid parameter number将 PHP PDO 迁移到 Laravel PDO 导致参数号无效
【发布时间】:2018-06-02 09:57:32
【问题描述】:

我正在将一个 PHP PDO 实例转换为 Laravel 5.5。我将数据库连接从/更改为:

//$dbc = new PDO ('mysql:host='. $DB_HOST .';dbname='. $DB_NAME, $DB_USER, $DB_PASS);
$dbc = \Illuminate\Support\Facades\DB::connection('foobardb')->getPdo();

由于某种原因,这导致我的 SELECT 查询失败。

$query = "SELECT *
          FROM foobartable
          WHERE date_created > :sunday
          AND date_created <= :monday
          AND date_updated > :sunday
          AND date_updated <= :monday";

$stmt = $dbc->prepare($query);
$stmt->bindValue(':monday', $monday, PDO::PARAM_STR);
$stmt->bindValue(':sunday', $sunday, PDO::PARAM_STR);
$stmt->execute();

$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

根据堆栈跟踪,该错误是专门在$stmt-&gt;execute();上触发的

SQLSTATE[HY093]: 参数号无效

我显然有correct parameters,并且使用 PHP 的 PDO 实例可以正常工作,那么为什么它不适用于 Laravel?

【问题讨论】:

  • 请记住,您通常可以使用 date_updated BETWEEN ? and ? 简化这种查询,而不必单独指定边界。
  • 这是一个好点,我经常忘记这一点。
  • BETWEEN 使用封闭边界,因此 WHERE a BETWEEN b AND c 转换为 a &gt;= b AND a &lt;= c。要确定这是否等同于您尝试实施的规则,您必须查看绑定值类型和数据库字段类型以查看边界是否正确重合(例如日期/日期时间/unix时间戳/等)

标签: php mysql laravel pdo laravel-5.5


【解决方案1】:

由于某种原因,Laravel 连接不会自动使用PDO::ATTR_EMULATE_PREPARES。就算有mysql连接。只需在连接数组中添加选项即可解决此问题。

'foobardb' => [
    'driver'    => 'mysql',
    'host'      => env('DB_HOST', 'localhost'),
    'port'      => env('DB_PORT', 3306),
    'database'  => 'foobardb',
    'username'  => env('DB_USERNAME', 'forge'),
    'password'  => env('DB_PASSWORD', ''),
    'charset'   => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix'    => '',
    'strict'    => false,
    'engine'    => null,
    //add addition options here
    'options'   => [PDO::ATTR_EMULATE_PREPARES => true]
],

我不知道这是否仅限于 Laravel 5.5,或者是否需要在早期版本中添加该选项。

解决此问题的另一种方法是执行以下操作:

$query = "SELECT *
          FROM foobartable
          WHERE date_created > :sunday
          AND date_created <= :monday
          AND date_updated > :sunday2
          AND date_updated <= :monday2";

然后:

$stmt->bindValue(':monday', $monday, PDO::PARAM_STR);
$stmt->bindValue(':sunday', $sunday, PDO::PARAM_STR);
$stmt->bindValue(':monday2', $monday, PDO::PARAM_STR);
$stmt->bindValue(':sunday2', $sunday, PDO::PARAM_STR);

这样它就会认为你拥有的 PDO 令牌数量与你拥有的 bindValues 数量相同。

【讨论】:

  • 您还可以通过向execute() 方法提供关联数组来一次绑定多个值。
  • 没有PDO::ATTR_EMULATE_PREPARES 也可以吗?
  • 我不知道那里有什么不同,只是它们的传递方式不同。
  • @tadman - 在这种情况下(使用数组)的键将被强制唯一。 (因为它们将是数组的键)所以让两个数组项的键为“星期天”但具有不同的值是没有意义的。
  • @ArtisticPhoenix 关联数组对唯一键有限制,但这也适用于占位符名称,因此它可以避免错误假设 bindValue 调用的顺序很重要,或者两个对同一个占位符使用不同值的调用意味着注入了两个不同的值,这不会发生。
猜你喜欢
  • 2018-12-01
  • 1970-01-01
  • 2016-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
  • 1970-01-01
  • 2012-07-09
相关资源
最近更新 更多