Skip to content

并发请求时使用数据库缓存机制报错only array cache can be push和think\db\PDOConnection::pdoQuery(): Return value must be of type array, bool returned #3132

@augushong

Description

@augushong

所属功能组件

路由(ORM/CACHE)

ThinkPHP 版本

8.1.3

操作系统

centos

错误信息

复现

创建一个新项目,修改代码app\controller\Index.php:

<?php

namespace app\controller;

use app\BaseController;
use think\facade\Cache;
use think\facade\Db;
use think\facade\View;

class Index extends BaseController
{
    public function index()
    {
        if($this->request->isAjax()){
            $r = Db::name('system_admin')->cache('key',null,null)->where('id',1)->find();
            Cache::delete('key');
            $r = Db::name('system_admin')->cache('key',null,null)->where('id',1)->find();
    
            dump($r);
        }

        return View::fetch();
    }

    public function hello($name = 'ThinkPHP8')
    {
        return 'hello,' . $name;
    }
}

修改页面view\index\index.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        function fetchData(url = '', options = {}) {
            // 添加默认的AJAX标志
            const defaultOptions = {
                headers: {
                    'X-Requested-With': 'XMLHttpRequest'
                }
            };

            // 合并默认选项和用户提供的选项
            const mergedOptions = {
                ...defaultOptions,
                ...options,
                headers: {
                    ...defaultOptions.headers,
                    ...options.headers
                }
            };

            return fetch(url, mergedOptions)
                .then(response => {
                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status}`);
                    }
                    return response.json();
                })
                .catch(error => {
                    console.error('请求出错:', error);
                    throw error;
                });
        }
        fetchData()
        fetchData()
        fetchData()
        fetchData()
        fetchData()
        fetchData()
        fetchData()
        fetchData()
        fetchData()
    </script>
</body>
</html>

此时访问页面,能够发现多个报错:

Image

报错1:only array cache can be push

Image

报错2:think\db\PDOConnection::pdoQuery(): Return value must be of type array, bool returned

Image

复现代码分析

控制中先进行一次查询,设置缓存名称,
第二步(重要),业务更具实际情况,删除了缓存,此处用户如果不主动删除,使用缓存自动更新机制,也会出问题:

            $r = Db::name('system_admin')->cache('user_data')->select([1,3,5]);
            $r = Db::name('system_admin')->cache('user_data')->update(['id'=>1,'update_time'=>time()]);
            $r = Db::name('system_admin')->cache('user_data')->select([1,3,5]);

第三步试图再次查询刚才的缓存信息。

一旦在并发请求下,就会很容易复现出这两个报错。

使用默认的文件缓存,如果redis报错会更容易复现(以前项目遇到过,发现file要好一些,从redis改为了file)。

这种写法很常见

比如我们在控制器基类里查询管理员账号信息,此时启用数据库缓存,部分逻辑里查询后做了一些更新,然后我们主动删除缓存,后续的代码中又有这个管理员账号信息的查询。一般情况下不会有问题,但如果我们页面上要打开表单时,表单上有很多下拉列表通过接口加载,会大量的请求接口,会很容易触发这个bug。

即便不存在第三步“再次进行相同查询”,并发时也会出现这种错误,情况并不会有更好的改善。

其它说明

league/flysystem 1.1.10 Filesystem abstraction: Many filesystems, one API.
league/flysystem-cached-adapter 1.1.0 An adapter decorator to enable meta-data caching.
league/mime-type-detection 1.16.0 Mime-type detection for Flysystem
psr/cache 1.0.1 Common interface for caching libraries
psr/container 2.0.2 Common Container Interface (PHP FIG PSR-11)
psr/http-message 1.1 Common interface for HTTP messages
psr/log 3.0.2 Common interface for logging libraries
psr/simple-cache 3.0.0 Common interfaces for simple caching
symfony/polyfill-mbstring 1.31.0 Symfony polyfill for the Mbstring extension
symfony/var-dumper 7.2.3 Provides mechanisms for walking through any arbitrary PHP variable
topthink/framework 8.1.2 The ThinkPHP Framework.
topthink/think-container 3.0.1 PHP Container & Facade Manager
topthink/think-dumper 1.0.5 Dumper extend for thinkphp
topthink/think-filesystem 2.0.3 The ThinkPHP6.1 Filesystem Package
topthink/think-helper 3.1.10 The ThinkPHP6 Helper Package
topthink/think-orm 4.0.9 the PHP Database&ORM Framework
topthink/think-template 3.0.2 the php template engine
topthink/think-trace 1.6 thinkphp debug trace
topthink/think-validate 3.0.5 think validate
topthink/think-view 2.0.5 thinkphp template driver

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions