-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
所属功能组件
路由(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>
此时访问页面,能够发现多个报错:
报错1:only array cache can be push
报错2:think\db\PDOConnection::pdoQuery(): Return value must be of type array, bool returned
复现代码分析
控制中先进行一次查询,设置缓存名称,
第二步(重要),业务更具实际情况,删除了缓存,此处用户如果不主动删除,使用缓存自动更新机制,也会出问题:
$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