数据库 SQL 操作
当数据模型 SDK 无法满足复杂查询需求时,可以直接使用 SQL 语句进行数据库操作。
提示
此方法仅支持服务端调用
SQL 语法支持范围
当前支持的 SQL 语句类型:
SELECT
- 数据查询INSERT
- 数据插入UPDATE
- 数据更新DELETE
- 数据删除
⚠️ 注意:不支持事务(Transaction)、存储过程、触发器等高级数据库功能
适用场景
- 复杂的多表联查
- 聚合函数和统计查询
- 批量数据操作
- 性能优化查询
查询方法
MySQL 数据模型提供两种 SQL 查询方式:
方法 | 说明 | 安全性 | 推荐度 |
---|---|---|---|
$runSQL | 预编译模式,参数化查询 | 高(防 SQL 注入) | ⭐⭐⭐ |
$runSQLRaw | 原始模式,直接执行 SQL | 低(需自行防护) | ⭐ |
⚠️ 注意:仅支持服务端调用(云函数、云托管等),建议优先使用
$runSQL
预编译模式
SDK 初始化
安装依赖
npm install @cloudbase/node-sdk --save
初始化代码
import cloudbase from "@cloudbase/node-sdk"
// 云函数环境下使用 require 方式
// const cloudbase = require('@cloudbase/node-sdk')
// 初始化应用
const app = cloudbase.init({
env: "your-env-id" // 替换为您的环境 ID
})
// 获取数据模型实例
const models = app.models
💡 注意:详细的初始化配置请参考 SDK 初始化 文档
预编译模式 $runSQL
使用参数化查询,通过 Mustache 语法({{ }}
)绑定参数,有效防止 SQL 注入。
SELECT 查询示例
// 条件查询
const result = await models.$runSQL(
"SELECT * FROM `table_name` WHERE title = {{title}} LIMIT 10",
{ title: "hello" }
);
// 数值比较
const result = await models.$runSQL(
"SELECT * FROM `table_name` WHERE read_num > {{num}}",
{ num: 1000 }
);
// 时间范围查询
const result = await models.$runSQL(
"SELECT * FROM `table_name` WHERE updatedAt > UNIX_TIMESTAMP({{timestamp}}) * 1000",
{ timestamp: "2024-06-01 00:00:00" }
);
// LIKE 模糊查询
const result = await models.$runSQL(
"SELECT * FROM `table_name` WHERE author_tel LIKE {{tel}}",
{ tel: "1858%" }
);
// 聚合统计
const result = await models.$runSQL(
"SELECT COUNT(*) as total FROM `table_name` WHERE is_published = {{isPublished}}",
{ isPublished: true }
);
// 指定字段查询
const result = await models.$runSQL(
"SELECT read_num, title FROM `table_name` ORDER BY read_num DESC"
);
INSERT/UPDATE/DELETE 示例
⚠️ 注意:INSERT操作时必须传入唯一标识
_id
字段,否则数据将没有唯一标识,可能导致后续查询和更新操作出现问题
// 插入数据(必须包含_id唯一标识)
const insertResult = await models.$runSQL(
"INSERT INTO `table_name` (_id, title, content, author) VALUES ({{id}}, {{title}}, {{content}}, {{author}})",
{
id: "article_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9), // 生成唯一ID
title: "新文章",
content: "文章内容",
author: "作者名"
}
);
// 批量插入数据
const batchInsertResult = await models.$runSQL(
"INSERT INTO `table_name` (_id, title, status) VALUES ({{id1}}, {{title1}}, {{status1}}), ({{id2}}, {{title2}}, {{status2}})",
{
id1: "article_" + Date.now() + "_001",
title1: "文章1",
status1: "published",
id2: "article_" + Date.now() + "_002",
title2: "文章2",
status2: "draft"
}
);
// 更新数据
const updateResult = await models.$runSQL(
"UPDATE `table_name` SET read_num = read_num + 1 WHERE _id = {{id}}",
{ id: "article_id_123" }
);
// 删除数据
const deleteResult = await models.$runSQL(
"DELETE FROM `table_name` WHERE status = {{status}} AND updatedAt < {{date}}",
{
status: "draft",
date: "2024-01-01 00:00:00"
}
);
💡 注意:
_id
字段建议使用以下方式生成唯一标识:
- 时间戳 + 随机字符串:
"prefix_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9)
- UUID库:使用
uuid
包生成标准UUID- 业务相关ID:结合业务逻辑生成有意义的唯一标识
返回结果格式
// SELECT 查询返回示例
{
"data": {
"total": 1,
"executeResultList": [{
"_id": "9JXU7BWFZJ",
"title": "hello",
"read_num": 997,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-02T00:00:00.000Z"
}],
"backendExecute": "27"
},
"requestId": "16244844-19fe-4946-8924-d35408ced576"
}
// INSERT/UPDATE/DELETE 操作返回示例
{
"data": {
"total": 1, // 影响的行数
"executeResultList": [],
"backendExecute": "15"
},
"requestId": "16244844-19fe-4946-8924-d35408ced576"
}
原始模式 $runSQLRaw
用于动态表名等特殊场景,需要自行处理 SQL 注入防范。
基础用法
// 直接执行 SQL 语句
const result = await models.$runSQLRaw(
"SELECT * FROM `table_name` WHERE title = 'hello' LIMIT 10"
);
// 动态表名场景(需确保表名来源安全)
const tableName = getValidTableName(); // 必须验证表名安全性
const result = await models.$runSQLRaw(
`SELECT * FROM \`${tableName}\` WHERE status = 'active'`
);
// 复杂查询示例
const result = await models.$runSQLRaw(`
SELECT t1.title, t2.category_name, COUNT(t3.comment_id) as comment_count
FROM articles t1
LEFT JOIN categories t2 ON t1.category_id = t2._id
LEFT JOIN comments t3 ON t1._id = t3.article_id
WHERE t1.status = 'published'
GROUP BY t1._id, t2.category_name
ORDER BY comment_count DESC
LIMIT 20
`);
安全注意事项
预编译模式安全建议
- 优先选择:除非必要,始终使用
$runSQL
预编译模式 - 参数绑定:所有用户输入都通过参数绑定传递,避免直接拼接
- 类型验证:确保参数类型与数据库字段类型匹配
原始模式安全要求
使用 $runSQLRaw
时必须严格遵守:
- 输入验证:严格验证和过滤所有用户输入
- 白名单机制:只允许预定义的安全值(如表名、字段名)
- 特殊字符转义:正确处理单引号、反引号等 SQL 特殊字符
- 错误处理:避免向客户端暴露详细的数据库错误信息
- 权限控制:确保执行 SQL 的账户具有最小必要权限
// ❌ 危险示例 - 直接拼接用户输入
const userInput = req.body.title;
const result = await models.$runSQLRaw(
`SELECT * FROM articles WHERE title = '${userInput}'`
);
// ✅ 安全示例 - 使用预编译模式
const result = await models.$runSQL(
"SELECT * FROM articles WHERE title = {{title}}",
{ title: req.body.title }
);