framework icon indicating copy to clipboard operation
framework copied to clipboard

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

Open augushong opened this issue 9 months ago • 0 comments

所属功能组件

路由(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

augushong avatar Mar 31 '25 06:03 augushong