模型删除数据 (Model Delete)
概述
Yao 提供了多种删除数据的方法,支持单条记录删除和批量删除,同时兼容软删除(Soft Delete)和永久删除(Hard Delete)两种模式。本文档详细介绍各种删除方式的特点、参数和使用场景。
删除方法概览
方法名称 | 功能描述 | 支持软删除 | 使用场景 |
---|---|---|---|
Delete | 删除单条记录 | ✅ 支持 | 需要保留删除记录的单条删除 |
Destroy | 永久删除单条记录 | ❌ 不支持 | 彻底清除数据的单条删除 |
DeleteWhere | 条件批量删除 | ✅ 支持 | 需要保留删除记录的批量删除 |
DestroyWhere | 条件批量永久删除 | ❌ 不支持 | 彻底清除数据的批量删除 |
软删除机制
软删除说明
软删除不会真正从数据库中移除数据,而是通过添加删除时间标记(默认字段名deleted_at
)来标识记录已被"删除"。这些被标记的记录在常规查询中不会被检索到,但仍然保存在数据库中,可以在需要时恢复。
配置软删除
在模型 JSON 定义中启用软删除功能:
json
{
"option": {
"soft_deletes": true // 开启软删除功能
}
}
基本用法详解
Delete 方法
用于删除单条记录,支持软删除。
参数说明:
- 参数1:记录ID或主键值
返回值:
- 成功:返回被删除记录的条数(通常为1)
- 失败:抛出异常
示例代码:
javascript
// 通过 ID 删除单条记录
function deleteRecord() {
// 删除ID为10的记录
return Process('models.category.delete', 10);
}
// 通过变量传入ID
function deleteById(id) {
return Process('models.category.delete', id);
}
Destroy 方法
用于永久删除单条记录,不支持恢复。
参数说明:
- 参数1:记录ID或主键值
返回值:
- 成功:返回被删除记录的条数(通常为1)
- 失败:抛出异常
示例代码:
javascript
// 永久删除指定 ID 的记录
function destroyRecord() {
// 永久删除ID为9的记录
return Process('models.category.destroy', 9);
}
// 在事务中使用永久删除
function destroyWithTransaction(id) {
const q = new Query();
// 开始事务
q.Run({
sql: {
stmt: 'START TRANSACTION;'
}
});
let success = true;
let result;
try {
// 执行其他操作...
// 永久删除记录
result = Process('models.category.destroy', id);
// 继续其他操作...
} catch (err) {
success = false;
console.log('永久删除操作失败:', err.message);
}
// 根据操作结果提交或回滚
if (success) {
q.Run({
sql: {
stmt: 'COMMIT;'
}
});
return result;
} else {
q.Run({
sql: {
stmt: 'ROLLBACK;'
}
});
return { success: false, message: '操作失败,已回滚' };
}
}
DeleteWhere 方法
用于条件批量删除记录,支持软删除。
参数说明:
- 参数1:查询条件对象,格式为
{ wheres: [...] }
返回值:
- 成功:返回被删除记录的条数
- 失败:抛出异常
示例代码:
javascript
// 简单条件批量删除
function deleteBySimpleCondition() {
return Process('models.category.deletewhere', {
wheres: [
{ column: 'parent_id', value: 4 },
{ column: 'status', value: 'inactive' }
]
});
}
// 使用多种操作符的条件删除
function deleteWithOperators() {
return Process('models.category.deletewhere', {
wheres: [
{ column: 'created_at', op: '<', value: '2023-01-01' },
{ column: 'view_count', op: '<=', value: 10 }
]
});
}
DestroyWhere 方法
用于条件批量永久删除记录,不支持恢复。
参数说明:
- 参数1:查询条件对象,格式为
{ wheres: [...] }
返回值:
- 成功:返回被删除记录的条数
- 失败:抛出异常
示例代码:
javascript
// 条件批量永久删除
function destroyByCondition() {
return Process('models.category.destroywhere', {
wheres: [{ column: 'parent_id', value: 4 }]
});
}
// 组合条件永久删除
function destroyWithMultipleConditions() {
return Process('models.category.destroywhere', {
wheres: [
{ column: 'status', value: 'archived' },
{ column: 'updated_at', op: '<', value: '2022-01-01' }
]
});
}
高级用法
复杂条件删除
使用多种条件组合和逻辑操作符实现复杂的删除逻辑。
javascript
// 使用复杂条件和逻辑操作符
function complexDelete() {
return Process('models.category.deletewhere', {
wheres: [
{ column: 'parent_id', op: '>', value: 4 },
{ column: 'created_at', op: '<', value: '2023-01-01' },
{ method: 'or', column: 'status', value: 'archived' },
{
method: 'where',
wheres: [
{ column: 'view_count', op: '<', value: 100 },
{ column: 'is_public', value: true }
]
}
]
});
}
嵌套条件删除
使用嵌套条件实现更复杂的逻辑组合。
javascript
// 使用嵌套条件组合
function nestedConditionDelete() {
return Process('models.category.deletewhere', {
wheres: [
{ column: 'status', value: 'published' },
{
method: 'where',
wheres: [
{ method: 'or', column: 'view_count', op: '<', value: 10 },
{ method: 'or', column: 'comment_count', op: '=', value: 0 }
]
}
]
});
}
关联删除
删除记录时同时处理关联数据。
javascript
// 删除分类时同时删除相关书籍
function deleteWithRelated() {
return Process('models.category.destroywhere', {
wheres: [{ column: 'id', value: 1 }],
withs: ['books'] // 同时删除关联的书籍
});
}
// 删除前检查关联数据
function safeDeleteWithCheck() {
// 先查询是否有关联数据
const hasRelated = Process('models.category.find', 1, {
withs: { books: { select: ['id'], limit: 1 } }
});
// 判断是否有关联书籍
if (hasRelated.books && hasRelated.books.length > 0) {
throw new Error('该分类下有关联书籍,请先删除或转移书籍');
}
// 安全删除
return Process('models.category.delete', 1);
}
常见模式与最佳实践
事务中的删除操作
在事务中执行删除操作,确保数据一致性。
javascript
// 在事务中执行多个删除操作
function transactionalDelete() {
const q = new Query();
// 开始事务
q.Run({
sql: {
stmt: 'START TRANSACTION;'
}
});
let hasError = false;
let categoryResult, tagsResult;
try {
// 删除分类
categoryResult = Process('models.category.delete', 5);
// 相关数据清理
tagsResult = Process('models.tag.deletewhere', {
wheres: [{ column: 'category_id', value: 5 }]
});
} catch (err) {
hasError = true;
console.log('删除操作失败:', err.message);
}
// 根据操作结果提交或回滚事务
if (hasError) {
q.Run({
sql: {
stmt: 'ROLLBACK;'
}
});
return { success: false, message: '删除操作失败,已回滚' };
} else {
q.Run({
sql: {
stmt: 'COMMIT;'
}
});
return { success: true, category: categoryResult, tags: tagsResult };
}
}
// 使用事务进行批量操作的另一个示例
function batchDeleteWithTransaction(ids) {
const q = new Query();
// 开始事务
q.Run({
sql: {
stmt: 'START TRANSACTION;'
}
});
let success = true;
const results = [];
// 循环删除多个记录
for (const id of ids) {
try {
const result = Process('models.category.delete', id);
results.push({ id: id, result: result });
} catch (err) {
success = false;
results.push({ id: id, error: err.message });
break;
}
}
// 根据操作结果提交或回滚
if (success) {
q.Run({
sql: {
stmt: 'COMMIT;'
}
});
console.log('所有删除操作已提交');
} else {
q.Run({
sql: {
stmt: 'ROLLBACK;'
}
});
console.log('由于错误,所有删除操作已回滚');
}
return { success: success, results: results };
}
批量删除与分页处理
处理大量数据删除时的分页处理模式。
javascript
// 分批删除大量数据
function batchDeleteInChunks() {
const pageSize = 100;
let page = 1;
let totalDeleted = 0;
// 循环分批删除
while (true) {
// 查询一批数据
const records = Process('models.category.paginate', {
wheres: [{ column: 'status', value: 'archived' }],
page: page,
pagesize: pageSize
});
if (!records.data || records.data.length === 0) {
break; // 没有更多数据,退出循环
}
// 提取ID列表
const ids = records.data.map((item) => item.id);
// 批量删除
const result = Process('models.category.destroywhere', {
wheres: [{ column: 'id', op: 'in', value: ids }]
});
totalDeleted += result;
page++;
// 可选:添加延迟,减轻数据库压力
// Process('utils.sleep', 1000); // 暂停1秒
}
return totalDeleted;
}
错误处理与调试
javascript
// 带错误处理的删除操作
function safeDelete(id) {
try {
const result = Process('models.category.delete', id);
return { success: true, count: result };
} catch (err) {
console.log('删除失败:', err.message);
return { success: false, error: err.message };
}
}
// 调试模式删除(先查询后删除)
function debugDelete(id) {
// 先查询记录是否存在
const record = Process('models.category.find', id);
if (!record) {
return { success: false, message: '记录不存在' };
}
console.log('准备删除记录:', JSON.stringify(record));
// 执行删除
const result = Process('models.category.delete', id);
return { success: true, deletedRecord: record, result: result };
}
软删除恢复操作
javascript
// 恢复软删除的记录
function restoreDeleted(id) {
// 查询包含已删除记录的数据
const record = Process('models.category.find', id, {
with_trashed: true // 包含已软删除的记录
});
if (!record) {
return { success: false, message: '记录不存在' };
}
// 检查记录是否被软删除
if (!record.deleted_at) {
return { success: false, message: '记录未被删除' };
}
// 恢复记录(将 deleted_at 设为 null)
const result = Process('models.category.save', {
id: id,
deleted_at: null
});
return { success: true, result: result };
}
// 使用自定义条件查询已删除记录
function queryDeletedRecords() {
return Process('models.category.get', {
wheres: [
{ column: 'status', value: 'archived' },
创建文件: `modesl/category.yao`
{ column: 'deleted_at', op: 'notnull' } // 明确查询已软删除的记录
]
});
}
完整模型定义示例
json
{
"name": "书籍分类",
"table": {
"name": "category",
"comment": "书籍分类表"
},
"columns": [
{
"label": "ID",
"name": "id",
"type": "ID",
"comment": "主键",
"primary": true
},
{
"label": "分类名称",
"name": "name",
"type": "string",
"length": 50,
"comment": "分类名称",
"nullable": false,
"index": true
},
{
"label": "父分类ID",
"name": "parent_id",
"type": "integer",
"comment": "父分类ID,顶级分类为0",
"default": 0
},
{
"label": "状态",
"name": "status",
"type": "string",
"comment": "状态:published-已发布,draft-草稿,archived-已归档",
"default": "published"
},
{
"label": "排序",
"name": "sort",
"type": "integer",
"comment": "排序值,越小越靠前",
"default": 100
}
],
"relations": {
"books": {
"type": "hasMany",
"model": "book",
"key": "category_id",
"foreign": "id"
}
},
"option": {
"timestamps": true,
"soft_deletes": true
},
"values": [
{ "id": 1, "name": "技术", "parent_id": 0 },
{ "id": 2, "name": "文学", "parent_id": 0 }
]
}
注意事项
软删除特性:
- 软删除记录实际上仍然保存在数据库中,只是设置了
deleted_at
不为null - 常规查询不会检索软删除的记录,需要使用自定义条件查询
- 软删除记录占用数据库空间,长期积累可能影响性能
- 软删除记录实际上仍然保存在数据库中,只是设置了
永久删除风险:
- Destroy相关方法执行的是真正的DELETE操作,数据无法恢复
- 建议在执行永久删除前进行确认或数据备份
- 生产环境中谨慎使用批量永久删除
批量删除注意事项:
- 大量数据批量删除可能导致数据库锁定和性能问题
- 建议使用事务并考虑分批处理
- 批量删除前先估算影响范围,例如使用count方法
关联数据处理:
- 删除记录前应考虑关联数据的处理策略
- 设置适当的外键约束或在代码中处理关联
- 可以使用事务确保关联数据一致性
性能优化:
- 删除大量数据考虑使用原生SQL或分批处理
- 定期清理软删除数据可以优化数据库性能
- 为常用查询条件字段添加适当的索引
相关主题
- 模型查询:用于在删除前查询数据
- 模型关联:了解关联数据的处理方式
- 数据库事务:确保数据一致性
- 模型钩子:在删除前后执行自定义逻辑