本文目录导读:

在 ThinkPHP 项目中实现数据还原与回收站功能,通常涉及软删除(逻辑删除)、备份还原以及中间表等核心概念,下面从这几个维度进行详细梳理并提供代码实现方案。
软删除(回收站的核心)
这是实现“回收站”最基础且最常用的技术,软删除的本质是不执行物理 DELETE,而是执行 UPDATE(设置 delete_time 字段)。
数据表设计
至少需要一个字段来标记是否被删除:
ALTER TABLE `user` ADD COLUMN `delete_time` INT UNSIGNED NULL DEFAULT NULL COMMENT '删除时间,NULL表示未删除';
模型定义
在 ThinkPHP 6/8 中,使用内置的软删除 Trait:
<?php
namespace app\common\model;
use think\Model;
use think\model\concern\SoftDelete;
class User extends Model
{
use SoftDelete; // 引入软删除功能
// 设置软删除字段(默认就是 delete_time,无需重复设置)
protected $deleteTime = 'delete_time';
// 开启自动时间戳(如果需要记录创建/更新时间)
protected $autoWriteTimestamp = true;
}
控制器中的 CRUD(回收站/还原演示)
<?php
namespace app\index\controller;
use app\common\model\User;
class UserController
{
// 1. 移入回收站(软删除)
public function recycle($id)
{
// 使用 destroy() 方法会触发软删除
$result = User::destroy($id);
// 或者:$user = User::find($id); $user->delete();
return json(['status' => $result ? 1 : 0]);
}
// 2. 查看回收站列表(只查被软删除的数据)
public function trashList()
{
// 使用 onlyTrashed() 方法查询被软删除的数据
$list = User::onlyTrashed()->select();
return json($list);
}
// 3. 还原数据(从回收站恢复)
public function restore($id)
{
// 找到被软删除的数据
$user = User::withTrashed()->find($id);
if ($user) {
// 使用 restore() 方法还原
$user->restore();
return json(['status' => 1]);
}
return json(['status' => 0, 'msg' => '数据不存在']);
}
// 4. 彻底删除(清空回收站)
public function forceDelete($id)
{
$user = User::withTrashed()->find($id);
if ($user) {
// force() 方法表示强制物理删除
$user->force()->delete();
return json(['status' => 1]);
}
return json(['status' => 0, 'msg' => '数据不存在']);
}
// 5. 正常查询列表(自动排除已删除的数据)
public function index()
{
// 常规查询会自动忽略软删除的数据
$list = User::select();
return json($list);
}
}
注意:如果涉及关联模型(如订单下的商品),需要同步配置关联的软删除,或者在业务层处理级联逻辑。
数据库备份与恢复(物理层面还原)
如果你指的是误删数据后的恢复(比如整个数据库表被清空),则可通过SQL 文件备份来实现。
使用 ThinkPHP 的 Db 类导出 SQL
以下是一个简单的备份控制器示例:
<?php
namespace app\admin\controller;
use think\facade\Db;
use think\response\Download;
class BackupController
{
// 数据库备份
public function backup()
{
// 读取所有表名
$tables = Db::getTables();
$sql = "-- ThinkPHP Database Backup\n";
$sql .= "-- Date: " . date('Y-m-d H:i:s') . "\n\n";
foreach ($tables as $table) {
// 生成建表语句 (MySQL)
$createSql = Db::query("SHOW CREATE TABLE `{$table}`");
$sql .= "-- 表结构: {$table}\n";
$sql .= $createSql[0]['Create Table'] . ";\n\n";
// 生成插入语句
$dataList = Db::table($table)->select();
foreach ($dataList as $data) {
$keys = implode('`, `', array_keys($data));
$values = implode("', '", array_map('addslashes', array_values($data)));
$sql .= "INSERT INTO `{$table}` (`{$keys}`) VALUES ('{$values}');\n";
}
$sql .= "\n";
}
// 保存为文件并下载
$filename = 'backup_' . date('Ymd_His') . '.sql';
file_put_contents($filename, $sql);
return download($filename, $filename);
}
// 数据库恢复 (上传SQL文件并执行)
public function restore()
{
// 假设通过请求接收文件 (upload)
$file = request()->file('file');
$sqlContent = file_get_contents($file->getRealPath());
// 分割SQL语句 (简单处理,根据分号分割)
$sqlArray = explode(";\n", $sqlContent);
Db::startTrans();
try {
foreach ($sqlArray as $sql) {
$sql = trim($sql);
if (!empty($sql)) {
Db::execute($sql); // 执行每条语句
}
}
Db::commit();
return json(['status' => 1]);
} catch (\Exception $e) {
Db::rollback();
return json(['status' => 0, 'msg' => $e->getMessage()]);
}
}
}
业务级“回收站”设计(复杂场景)
如果需要在回收站中区分不同类型的内容(比如文章、图片、分类),并支持按条件过滤,建议引入中间表或扩展字段管理。
表结构设计示例:
-- 删除记录表(回收站日志) CREATE TABLE `trash_items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `model_name` varchar(50) NOT NULL COMMENT '模型名,如 article', `data_id` int(11) NOT NULL COMMENT '原数据ID', `delete_user` varchar(50) DEFAULT NULL COMMENT '删除人', `delete_reason` varchar(255) DEFAULT NULL COMMENT '删除原因', `original_data` text COMMENT '序列化存储的原始数据JSON', `delete_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) );
操作流程:
- 删除时:除了进行模型软删除,同时将原始数据序列化存入
trash_items.original_data。 - 还原时:根据
model_name和data_id,反序列化数据,插入回原表,并清除回收站记录。 - 彻底清理:直接删除
trash_items记录。
这种方式更灵活,可以看到删除历史,也能防止不同模块的数据混淆。
总结与选择建议
| 场景 | 推荐方案 |
|---|---|
| 简单的文章/用户管理 | 使用模型软删除 (Trait SoftDelete) |
| 希望保留删除日志、原因 | 业务级 Log(中间表) |
| 数据库整体灾难恢复 | SQL 文件备份/恢复 |
| 缓存恢复(防止数据丢失) | 配合定时任务自动备份数据库 |
性能与安全提示:
- 软删除数据过多时,记得为
delete_time字段添加索引。 - 恢复 SQL 时,务必关闭外键检查
SET FOREIGN_KEY_CHECKS=0;,避免插入顺序导致失败。 - 回收站应定期清理(如超过30天的数据,通过计划任务执行彻底删除)。
如果你需要具体的原生 SQL 迁移或集成第三方备份插件(如 topthink/think-migration),可以告诉我你的具体版本(TP6 还是 TP8),我可以补充相应的代码细节。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播