前言:在实际项目中,对数据频繁使用删除操作会导致性能问题,软删除的作用就是把数据加上删除标记,而不是真正的删除,同时也便于需要的时候进行数据的恢复。
1.修改或者添加数据库字段
Thinkphp5 中默认的该字段是 delete_time,创建表的时候需要添加字段 delete_time。
例如:创建一个 user_list表。
CREATE TABLE `user_list` (
`key` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户表主键key',
`name` varchar(100) DEFAULT NULL COMMENT '登录用户名',
`user_name` varchar(100) DEFAULT NULL COMMENT '用户名',
`delete_time` int(11) unsigned DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`key`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;
其中的字段 delete_time 就是Thinkphp5 中默认的删除字段。
2.自定义删除字段
在 Thinkphp5 中在model类方法中可以自定义所需要的删除字段,不想用 delete_time 做删除字段也可以用其他的字段代替。
//定义数据表中软删除标记字段
protected $deleteTime = 'delete_time';//字段名可以自定义。
3.在model类中的使用
自定义一个 model 类 UserlistModel
<?php
namespace app\user\model;
use traits\model\SoftDelete;
use think\Model;
class UserlistModel extends Model
{
use SoftDelete;
//定义数据表中软删除标记字段
protected $deleteTime = 'delete_time';
//5.1以上版本才有defaultSoftDelete属性,设置软删除字段的默认值,5.0的默认值为NULL
protected $defaultSoftDelete = 0;
}
4.实际使用
定义好模型后,就可以使用软删除了,下面是软删除的2种使用方式:
//1.通过模型的静态方法
//软删除
UserlistModel::destroy(1);
UserlistModel::destroy(function($query){
$query->where('key','>',10);
});
UserlistModel::destroy(['status' => 0]);
//真实删除
UserlistModel::destroy(1,true);
//2.查询后调用 delete 方法
$user = UserlistModel::get(1);
//软删除
$user->delete();
//真实删除
$user->delete(true);
默认情况下查询的数据不包含软删除数据,如果需要包含软删除的数据,可以使用下面的方式查询:
//包含软删除的数据
UserlistModel::withTrashed()->find();
UserlistModel::withTrashed()->select();
如果仅仅需要查询软删除的数据,可以使用:
//仅查询软删除的数据
UserlistModel::onlyTrashed()->find();
UserlistModel::onlyTrashed()->select();
注:软删除仅对模型的删除方法有效,如果直接使用数据库的删除方法则无效,例如下面的方式无效(将不会执行任何操作)(只有查询后的模型调用 delete 方法会生效,直接调用 delete 方法的话无法调用模型事件)。
//这种写法无法实现软删除的功能
UserlistModel::where('key',1)->delete();
//这种方式才能是软删除
$user = UserlistModel::where('key',1)->find();
$user->delete();
5.thinkphp官方的SoftDelete trait性能上有些缺陷,改为引入 自定义的SoftDelete trait。
<?php
namespace app\base\model;//可以自定义命名空间
use traits\model\SoftDelete as Base;
trait SoftDelete
{
//组合核心库中软删除类
use Base;
/**
* 删除记录(重写核心库中destroy方法)
* @access public
* @param mixed $data 主键列表(支持闭包查询条件)
* @param bool $force 是否强制删除
* @return integer 成功删除的记录数
*/
public static function destroy($data, $force = false)
{
if (is_null($data)) {
return 0;
}
//包含软删除数据
$query = (new static())->db(false);
if (is_array($data) && key($data) !== 0) {
$query->where($data);
$data = null;
} elseif ($data instanceof \Closure) {
call_user_func_array($data, [ & $query]);
$data = null;
}
$count = 0;
$name = (new static())->getDeleteTimeField();
$key = (new static())->getPkField();
if ($resultSet = $query->field($key)->where($name, 'null')->select($data)) {
foreach ($resultSet as $data) {
$result = $data->delete($force);
$count += $result;
}
}
return $count;
}
/**
* 获取主键字段
* @access public
* @param bool $read 是否查询操作(写操作的时候会自动去掉表别名)
* @return string
*/
protected function getPkField($read = false)
{
$field = property_exists($this, 'pk') && isset($this->pk) ?
$this->pk :
'key';
if (false === $field) {
return false;
}
if (!strpos($field, '.')) {
$field = '__TABLE__.' . $field;
}
if (!$read && strpos($field, '.')) {
$array = explode('.', $field);
$field = array_pop($array);
}
return $field;
}
}
使用方法,直接在 model 方法中进行调用。
<?php
namespace app\daba\model;
use app\base\model\SoftDelete;//调用自定义的软删除类
use think\Model;
class UserlistModel extends Model
{
use SoftDelete;
protected $name = 'user_list';
//定义数据表中软删除标记字段
protected $deleteTime = 'delete_time';
//5.1以上版本才有defaultSoftDelete属性,设置软删除字段的默认值,5.0的默认值为NULL
protected $defaultSoftDelete = 0;
public static function getList()
{
return self::onlyTrashed()->select();
}
}