thinkphp实现软删除需在数据表添加delete_time字段用于标记删除状态;2. 模型中引入softdelete trait并配置相关字段即可自动将delete()转为更新操作;3. 查询时默认自动排除软删除数据,可用withtrashed()或onlytrashed()控制是否包含已删除数据;4. 恢复数据调用restore()方法即可将delete_time置空;5. 彻底删除可调用force()或delete(true)执行物理删除,确保灵活性与数据安全。

在ThinkPHP里实现软删除,核心思路其实很简单:我们不在数据库里真正删掉那条数据,而是给它打个“已删除”的标记。通常的做法是,在数据表里加一个 delete_time 字段,当需要“删除”时,就往这个字段里填上当前时间戳,而不是执行 DELETE 语句。这样一来,数据还在,只是被系统逻辑上“隐藏”了。ThinkPHP的ORM对这个功能有非常好的内置支持,用起来非常顺手。

要让你的ThinkPHP应用支持软删除,你需要做几件事。首先,数据库层面得有个字段来承载这个“删除标记”。我通常会用 delete_time,类型设为 DATETIME 或 TIMESTAMP,并且允许为空(NULL)。当数据正常存在时,这个字段就是 NULL;一旦被“删除”,就会被填充上删除时的时间。
接下来是模型层的配置。在你的模型类里,你需要引入 SoftDelete Trait,并指定你用来标记删除的字段名。比如,如果你的模型是 app\model\User:
立即学习“PHP免费学习笔记(深入)”;

<?php
namespace app\model;
use think\Model;
use think\model\SoftDelete; // 引入软删除Trait
class User extends Model
{
    // 使用软删除Trait
    use SoftDelete;
    // 定义软删除字段,默认是delete_time,如果你的字段名不同,需要在这里指定
    // protected $deleteTime = 'delete_time'; // 如果字段名就是delete_time,可以省略这行
    // 定义时间戳字段名,如果你的表里有create_time和update_time,通常也需要定义
    protected $createTime = 'create_time';
    protected $updateTime = 'update_time';
    // 如果你的主键不是id,也要在这里指定
    // protected $pk = 'user_id';
}完成这些配置后,当你对模型实例调用 delete() 方法时,ThinkPHP就不会真的去执行 DELETE FROM table WHERE id = xxx 了。它会悄悄地执行一个 UPDATE table SET delete_time = NOW() WHERE id = xxx 的操作。这感觉就像是给数据贴了个隐形标签,告诉系统:“嘿,这玩意儿暂时别显示了。”
比如,你想“删除”ID为1的用户:

use app\model\User;
$user = User::find(1);
if ($user) {
    $user->delete(); // 此时,user表的id为1的记录的delete_time字段会被填充
    echo "用户已标记为删除。";
}是不是很简单?感觉就像是ORM在背后帮你做了个小魔术。
说实话,我个人在项目里几乎是能用软删除就用,除非业务逻辑明确要求数据必须物理销毁(比如用户注销,需要符合GDPR等隐私法规时)。为什么呢?
首先,数据安全和可恢复性。这是最直观的好处。手一抖,或者业务逻辑没考虑周全,物理删除的数据就真的没了,想找回来简直是噩梦。但软删除不一样,它只是个标记,你随时可以把它“恢复”回来。想想看,如果一个电商平台,用户不小心删了订单,或者运营人员误删了商品,能一键恢复是多么重要的事情。这就像给你的数据买了一份保险。
其次,审计和追踪。很多时候,我们需要知道数据曾经的存在状态,或者谁在什么时候“删除了”它。软删除保留了数据的完整历史,方便我们进行审计和追踪。这对于金融、医疗等合规性要求高的行业尤其重要。
再来,用户体验。现在很多应用都有“回收站”或者“撤销”功能。软删除就是实现这些功能的基石。用户删了东西还能后悔,这种体验是物理删除无法提供的。
当然,软删除也不是万能药。它也有它的“副作用”。最明显的就是数据库体积膨胀。那些被标记为“删除”的数据依然占用存储空间。如果你的数据量非常大,并且有大量的软删除数据,可能会对数据库性能造成轻微影响,尤其是在没有正确索引的情况下。另外,查询的时候,如果需要排除软删除数据,可能会稍微增加查询复杂度(虽然ThinkPHP已经帮你处理好了)。但通常来说,这些问题在大多数应用场景下都是可控的,收益远大于成本。
既然数据只是被标记了,那在查询的时候,系统怎么知道哪些是“正常”的,哪些是“已删除”的呢?ThinkPHP的软删除功能非常智能,它默认的行为就是自动排除那些 delete_time 不为 NULL 的记录。这意味着,你平时写查询,比如 User::where('status', 1)->select();,它返回的就已经是“未删除”的数据了。
但有时候,我们就是需要看到那些“已删除”的数据,比如在后台管理系统里,管理员可能需要查看所有数据,包括被删除的,或者只是想看看哪些数据被删了。ThinkPHP提供了几个非常方便的方法来控制查询行为:
查询所有(包括软删除数据):
使用 withTrashed() 方法。
use app\model\User; // 获取所有用户,包括那些已经被软删除的 $allUsers = User::withTrashed()->select(); // 这会生成类似 SELECT * FROM user WHERE delete_time IS NULL OR delete_time IS NOT NULL 的查询,或者更直接的 SELECT * FROM user
只查询软删除数据:
使用 onlyTrashed() 方法。这在你想清理回收站或者查看删除历史时特别有用。
use app\model\User; // 只获取那些已经被软删除的用户 $trashedUsers = User::onlyTrashed()->select(); // 这会生成类似 SELECT * FROM user WHERE delete_time IS NOT NULL 的查询
这些方法可以很灵活地和其他查询条件链式调用,满足你各种复杂的查询需求。比如,你想找某个时间段内被删除的用户:
use app\model\User;
$recentTrashedUsers = User::onlyTrashed()
                            ->where('delete_time', '>', '2023-01-01 00:00:00')
                            ->select();软删除的魅力之一就是它的可逆性。既然只是打了个标记,那自然也能把这个标记“擦掉”,让数据重新“活”过来。同时,如果你真的想彻底清理掉一些数据,ThinkPHP也提供了相应的强制删除方法。
恢复软删除的数据:
使用模型实例的 restore() 方法。这会把 delete_time 字段重新设为 NULL。
use app\model\User;
// 假设我们知道某个被软删除的用户的ID是10
$trashedUser = User::onlyTrashed()->find(10);
if ($trashedUser) {
    $trashedUser->restore(); // 此时,ID为10的用户的delete_time字段会变回NULL
    echo "用户ID:10 已成功恢复。";
} else {
    echo "未找到ID为10的已删除用户。";
}你也可以批量恢复,但这需要你先查询出这些被删除的数据集合:
// 恢复所有在某个时间点后被删除的用户
User::onlyTrashed()->where('delete_time', '>', '2023-06-01 00:00:00')->restore();彻底删除(物理删除)软删除的数据:
有时候,你确实需要把数据从数据库里彻底抹掉,比如为了节省空间,或者出于合规性考虑。这时,你可以使用模型实例的 force() 方法,或者在 delete() 方法中传入 true 参数。
use app\model\User;
// 方式一:使用force()方法
$userToDeletePermanently = User::onlyTrashed()->find(5); // 找到一个已被软删除的用户
if ($userToDeletePermanently) {
    $userToDeletePermanently->force(); // 此时,ID为5的记录会被从数据库中物理删除
    echo "用户ID:5 已被物理删除。";
}
// 方式二:在delete()方法中传入true
$anotherUserToDelete = User::find(6); // 找到一个正常的用户
if ($anotherUserToDelete) {
    $anotherUserToDelete->delete(true); // 此时,ID为6的记录会被直接物理删除,不会走软删除逻辑
    echo "用户ID:6 已被物理删除。";
}值得注意的是,delete(true) 这种方式,无论你的模型是否开启了软删除,都会直接执行物理删除。而 force() 方法通常是在你已经查询出被软删除的数据后,再决定对其进行物理删除的操作。
在实际项目中,我通常会结合定时任务来清理那些“超期”的软删除数据,比如设置一个策略:被软删除超过90天的数据,就自动执行物理删除,这样既保证了短期内的数据可恢复性,又避免了数据库无限膨胀。这是一种比较平衡的做法。
以上就是ThinkPHP的软删除怎么实现?ThinkPHP如何标记删除数据?的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
 
                 
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                            Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号