【发布时间】:2018-05-18 04:25:40
【问题描述】:
TL;DR
我排队的作业有时似乎会失败,因为常规数据库查询(使用 Laravel 的标准查询构建器)不能可靠地返回我的config/database.php 中的 fetch 模式定义的 PHP 对象。它似乎有时会返回一个对象或一个数组,因此获取模式会以某种方式发生变化(甚至变回)。
详细问题
我正在使用 Laravel 的查询构建器查询外部数据库。 fetch模式设置为返回config/database.php中的对象:
'fetch' => PDO::FETCH_OBJ,
...基本上在我的应用程序的许多地方都可以使用。
有时,在将其作为排队作业执行时,查询的结果可能是数组而不是对象。作业运行正确的代码,我无法重现为什么有时会发生这种情况。
有人知道什么会导致这种结果吗?
例如,使用常规的get() 方法或chunk 都会发生这种情况。重新启动 queue runner 有助于消除错误,但它最终会回来!
我的代码如下所示:
$assetData = DB::connection('connection_name')->table('system')
->whereIn('system_id', $this->system_ids)->orderBy('system_id');
$emlAssetData->chunk(5000, function ($assetDataChunk) {
foreach ($assetDataChunk AS $assetData) {
if (!is_object($assetData)) {
\Log::warning(__CLASS__.': '.json_encode($assetData));
}
}
$assetData->field; // Sometimes fails because result is an array, instead of an object
}
我正在使用:
- PHP 7.0
- MySQL
v5.7.16v5.1.49 - Laravel 5.5
我的解决方法是将其添加到我查询这样的外部数据库的任何地方。
if (is_array($assetData)) {
\Log::warning(__CLASS__." Converting array to object: ".json_encode($assetData));
$assetData = (object)$assetData;
}
在这种情况下很难进行调试,因为它只发生在队列中运行:(
更新:2017-12-11:有关正在使用的 SQL/代码的更多详细信息
总结一下我在这里做的更特别的事情,可能与我的问题有关:
- 我查询的不是本地主机上运行的“默认”连接,而是外部数据库(在内部网络中)
- 我用的不是 Eloquent,而是 Laravel 的常规查询生成器
- 为了逐步查看结果,我使用了一个自己编写的自定义函数,它为每一行调用一个回调函数
背景:这会将旧数据库 MySQL v5.1.49 的各个部分导入我们项目的数据库。为了使这更容易,您可以像这样指定某种列映射(从旧字段/表名称到新字段/表名称)
$columnMapping = collect([
'system.system_id' => 'system_id',
'staud_colours.colour_name' => 'system_name',
]);
接下来,您执行自定义查询并使用辅助函数将旧字段映射到新字段:
$items = \DB::connection('slave')->table('system')
->join('staud_colours', 'staud_colours.colour_id', '=', 'system.system_fremd_id')
->where('system.system_klasse', 'colours')->where('system.system_status', 1);
$this->prepareQueryToBeInsertedToDB($items, $columnMapping, function ($insertData) {
static::create($insertData);
});
还有帮助函数,您可以在其中看到我添加的所有 ifs,因为我有时会收到一个数组而不是对象:
protected function prepareEmlQueryToBeInsertedToDB(
Builder $items,
Collection $columnMapping,
Closure $callback,
$orderBy = 'system.system_id'
) {
// Step through each element of the mapping
$items->orderBy($orderBy)->select($columnMapping->keys()->toArray())
->chunk(5000, function ($items) use ($columnMapping, $callback, $items) {
foreach ($items AS $item) {
$values = $columnMapping->mapWithKeys(function ($item, $key) use ($item) {
$key = Str::lower($key);
if (Str::contains($key, ' as ')) {
$column = array_reverse(explode(' as ', $key))[0];
} else {
$column = substr(strrchr($key, "."), 1);
}
if (!$item) {
\Log::error("Received damaged item from slave db: ".json_encode($item));
}
if (is_array($item)) {
$item = (object)$item;
}
if (!property_exists((object)$item, $column)) {
\Log::error("{$column} does not exist on item from slave db: ".json_encode($item));
}
$value = $item->$column;
return [$item => $value];
});
if (!$values || $values->isEmpty()) {
info('No values: '.json_encode($values));
}
// Now call the callback method for each item, passing an well prepared array in format:
// column_name => value
// so that it can be easily be used with something like static::create()
$callback($values->toArray());
}
});
}
【问题讨论】:
-
你能告诉我们所涉及的 SQL 查询吗?
-
是的,当然。我在原始问题中添加了更新
-
能否提供实际的 SQL 代码,而不仅仅是最终产生 SQL 代码的 Laravel 代码。
-
请参阅下面的答案,了解我的问题的根本原因。
标签: php mysql laravel laravel-5 pdo