跳到主要内容

数据库 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 }
);