禅道 20.3.0 开源版,备份时报错,导致备份SQL失败。
---
执行备份时,系统报错
Fatal error: Uncaught PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'zentao.metriclib_distinct' doesn't exist ,the sql is: 'select * from `metriclib_distinct`' in /apps/zentao/lib/dbh/dbh.class.php:107
Stack trace:
#0 /apps/zentao/lib/dbh/dbh.class.php(153): dbh->sqlError(Object(PDOException))
#1 /apps/zentao/lib/zdb/zdb.class.php(255): dbh->query('select * from `...')
#2 /apps/zentao/module/backup/model.php(25): zdb->dump('/apps/zentao/tm...')
#3 /apps/zentao/module/backup/zen.php(64): backupModel->backSQL('/apps/zentao/tm...')
#4 /apps/zentao/module/backup/control.php(197): backupZen->backupSQL('202407230139135...', 'yes')
#5 /apps/zentao/framework/base/router.class.php(2480): backup->backup('yes', 'manual')
#6 /apps/zentao/framework/router.class.php(770): baseRouter->loadModule()
#7 /apps/zentao/www/index.php(88): router->loadModule()
#8 {main} thrown in /apps/zentao/lib/dbh/dbh.class.php on line 107
---------------
使用 docker版本 20.3.0
MYSQL 8.0
-----------
全文搜索
metriclib_distinct 关键词,定位到:
\zentaopms\module\metric\tao.php 有这个临时表的建立函数。
但是在备份动作时,不知道什么原因,触发了对这个临时表的备份。(肯定是找不到的拉~)
![](/theme/default/default/images/main/icon-thread-score.png)
备份的逻辑分为两步,首先获取所有的表名,其次循环查询表的数据生成备份语句。
根据您的反馈,可能的原因是
1. 其他同事触发了临时表的建立函数 createDistinctTempTable,执行数据生成需要一定的时间
2. 备份的按钮触发,获取所有数据表时 metriclib_distinct 是在集合中的。
3. createDistinctTempTable ,执行删除表的操作
4. 备份的逻辑开始查询 metriclib_distinct 表的数据 (此时表已不存在,系统保存致命错误)
这块禅道的备份逻辑需要增强,在查询数据库表的数据时应判断表是否存在。
您再次点击备份应该可以成功。
或者执行完语句 DROP TABLE IF EXISTS `metriclib_distinct` ,后再备份。
我单机 一人 DOCKER部署 依然出现这个问题。
且 docker启动后 无人使用的情况下 这个报错的触发也非常频繁。
目前造成的问题在于 备份不稳定。
(可查看2次故障的间隔周期)
这块我们内部反馈一下。
你可以使用一个临时方案
1. 找到 lib/zdb/zdb.class.php
2. 第238行下面增加几行代码,用来再次判断表是否存在
```
/* Check table exists. */
$showTable = $this->dbh->query("show tables like `$table`")->fetch();
if(empty($showTable)) continue;
```
这块我们内部反馈一下。
你可以使用一个临时方案
1. 找到 lib/zdb/zdb.class.php
2. 第238行下面增加几行代码,用来再次判断表是否存在
```
/* Check table exists. */
$showTable = $this->dbh->query("show tables like `$table`")->fetch();
if(empty($showTable)) continue;
```
这个方法有效,是一个有效的补丁。
不过 在 MYSQL 8上
`$table` 需要改为 '$table'
否则会报错。
此外 由于目前禅道没有涉及事务处理,所以 show tables 在并发备份或者类似场景时,依然会 出现 判断错误的问题。
我临时的解决方案是:
本质上,这个问题要高效解决,建议是如下的思路去处理:
1、考虑使用 临时表而不是真实的表,例如:CREATE TEMPORARY TABLE
2、在这个基础上,使用事务处理,避免出现幻读问题。
恭喜解决了问题。
我们这边和开发团队沟通下解决方案 (反馈id6508),有最新的消息,在此回复。
![](https://cdn.easycorp.cn/web/data/contact/avatar/1481227768.png)
![](/theme/default/default/images/main/icon-contact-split.png)
![](/theme/default/default/images/main/icon-contact-split.png)
![](/theme/default/default/images/main/icon-contact-split.png)
![](https://cdn.easycorp.cn/web/data/contact/17663906485.png)