云开发 MySQL 数据库
云开发 MySQL 数据库为您提供了完全托管的关系型数据库服务,支持在云函数中进行高效的数据操作。本文档将详细介绍如何在云函数中使用 MySQL 数据库,包括连接配置、数据操作、事务处理等核心功能。
快速开始
📄️ 数据库连接
学习如何在云函数中连接 MySQL 数据库
📄️ 基础操作
掌握增删改查等基本数据库操作
📄️ 高级查询
关联查询、聚合查询等高级功能
📄️ 最佳实践
性能优化、错误处理等最佳实践
数据库连接
初始化 SDK
在使用 MySQL 数据库之前,需要先初始化云开发 SDK 并获取数据库引用:
- 基础连接
- 指定实例
- 云函数中使用
const cloudbase = require('@cloudbase/node-sdk');
// 初始化云开发 App 实例
const app = cloudbase.init({
env: 'your-env-id' // 替换为您的环境 ID
});
// 获取 MySQL 数据库引用(使用默认实例和数据库)
const db = app.rdb();
const cloudbase = require('@cloudbase/node-sdk');
const app = cloudbase.init({
env: 'your-env-id'
});
// 指定特定的实例和数据库
const db = app.rdb({
instance: 'your-instance-name',
database: 'your-database-name'
});
// 云函数入口文件
const cloudbase = require('@cloudbase/node-sdk');
const app = cloudbase.init({
env: cloudbase.SYMBOL_CURRENT_ENV // 使用当前环境
});
const db = app.rdb();
exports.main = async (event, context) => {
try {
// 在这里使用数据库操作
const { data, error } = await db.from('users').select();
return {
success: true,
data: data
};
} catch (error) {
console.error('数据库操作失败:', error);
return {
success: false,
error: error.message
};
}
};
基础操作
查询数据
使用 select() 方法查询表数据,支持条件筛选、关联查询等功能。
- 基础查询
- 条件查询
- 关联查询
// 查询所有数据
const { data, error } = await db.from('articles').select();
// 查询指定字段
const { data, error } = await db.from('articles').select('id, title, created_at');
// 使用 * 查询所有字段
const { data, error } = await db.from('articles').select('*');
console.log('查询结果:', data);
// 等值查询
const { data, error } = await db.from('articles')
.select('*')
.eq('status', 'published');
// 范围查询
const { data, error } = await db.from('articles')
.select('id, title')
.gt('created_at', '2024-01-01')
.lt('created_at', '2024-12-31');
// 包含查询
const { data, error } = await db.from('articles')
.select('*')
.in('category_id', [1, 2, 3]);
// 模糊查询
const { data, error } = await db.from('articles')
.select('*')
.like('title', '%云开发%');
// 基础关联查询
const { data, error } = await db.from('articles').select(`
id,
title,
categories(name)
`);
// 使用别名
const { data, error } = await db.from('articles').select(`
id,
title,
category:categories(name)
`);
// 多重关联(需要使用外键约束名区分)
const { data, error } = await db.from('articles').select(`
title,
creator:users!articles_created_by_fkey(name),
updater:users!articles_updated_by_fkey(name)
`);
// 嵌套关联
const { data, error } = await db.from('categories').select(`
name,
articles (
title,
users (name)
)
`);
插入数据
使用 insert() 方法向表中插入数据,支持单行插入和批量插入。
- 单条插入
- 批量插入
- 插入并返回
// 插入单条记录
const { error } = await db.from('articles').insert({
title: '云开发入门指南',
content: '这是一篇关于云开发的入门文章...',
author_id: 1,
status: 'draft'
});
if (error) {
console.error('插入失败:', error);
} else {
console.log('插入成功');
}
// 批量插入多条记录
const { error } = await db.from('articles').insert([
{
title: '第一篇文章',
content: '第一篇文章内容',
author_id: 1
},
{
title: '第二篇文章',
content: '第二篇文章内容',
author_id: 2
}
]);
console.log('批量插入结果:', error ? '失败' : '成功');
// 插入数据并返回结果(仅当表只有一个自增主键时有效)
const { data, error } = await db.from('articles').insert({
title: '新文章标题',
content: '文章内容'
}).select();
console.log('插入的数据:', data);
更新数据
使用 update() 方法更新表中的数据。注意:必须与过滤器结合使用。
- 单条更新
- 批量更新
- 条件更新
// 更新指定 ID 的记录
const { error } = await db.from('articles')
.update({
title: '更新后的标题',
status: 'published',
updated_at: new Date().toISOString()
})
.eq('id', 1);
console.log('更新结果:', error ? '失败' : '成功');
// 批量更新符合条件的记录
const { error } = await db.from('articles')
.update({
status: 'published'
})
.eq('status', 'draft')
.gt('created_at', '2024-01-01');
console.log('批量更新结果:', error ? '失败' : '成功');
// 使用多个条件更新
const { error } = await db.from('users')
.update({
last_login: new Date().toISOString(),
login_count: db.raw('login_count + 1') // 使用原生 SQL 表达式
})
.eq('email', 'user@example.com')
.eq('status', 'active');
删除数据
使用 delete() 方法删除表中的数据。注意:必须与过滤器结合使用。
- 单条删除
- 批量删除
- 条件删除
// 删除指定 ID 的记录
const { error } = await db.from('articles')
.delete()
.eq('id', 1);
console.log('删除结果:', error ? '失败' : '成功');
// 批量删除多条记录
const { error } = await db.from('articles')
.delete()
.in('id', [1, 2, 3]);
console.log('批量删除结果:', error ? '失败' : '成功');
// 删除符合条件的记录
const { error } = await db.from('articles')
.delete()
.eq('status', 'draft')
.lt('created_at', '2024-01-01');
console.log('条件删除结果:', error ? '失败' : '成功');
HTTP API 访问
除了 Node.js SDK,您也可以通过 HTTP API 直接访问 MySQL 数据库。HTTP API 基于 REST 规范,支持标准的 HTTP 方法进行数据操作。
基础配置
- 认证配置
- 环境变量
// HTTP API 请求需要包含认证信息
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-access-token',
// 或使用其他认证方式
'X-CloudBase-Credentials': 'your-credentials'
};
const baseURL = 'https://your-env-id.service.tcloudbase.com/v1/rdb/rest';
// 推荐使用环境变量管理配置
const config = {
baseURL: process.env.CLOUDBASE_API_URL || 'https://your-env-id.service.tcloudbase.com/v1/rdb/rest',
accessToken: process.env.CLOUDBASE_ACCESS_TOKEN,
envId: process.env.CLOUDBASE_ENV_ID
};
查询数据
使用 GET 方法查询表中的数据:
- 基础查询
- 条件查询
- 关联查询
# 查询所有数据
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users" \
-H "Authorization: Bearer your-access-token" \
-H "Content-Type: application/json"
# 查询指定字段
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?select=id,name,email" \
-H "Authorization: Bearer your-access-token"
# 分页查询
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?limit=10&offset=20" \
-H "Authorization: Bearer your-access-token"
# 等值查询
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?status=eq.active" \
-H "Authorization: Bearer your-access-token"
# 范围查询
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?age=gte.18&age=lte.65" \
-H "Authorization: Bearer your-access-token"
# 模糊查询
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?name=like.*张*" \
-H "Authorization: Bearer your-access-token"
# 排序查询
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?order=created_at.desc" \
-H "Authorization: Bearer your-access-token"
# 关联查询
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/articles?select=id,title,categories(name)" \
-H "Authorization: Bearer your-access-token"
# 多层关联
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/categories?select=name,articles(title,users(name))" \
-H "Authorization: Bearer your-access-token"
# 使用别名
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/articles?select=id,title,category:categories(name)" \
-H "Authorization: Bearer your-access-token"
JavaScript 调用示例
- 查询数据
- 插入数据
- 更新数据
- 删除数据
// 查询用户列表
async function queryUsers() {
try {
const response = await fetch(`${config.baseURL}/users?select=*&limit=20`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const users = await response.json();
console.log('查询结果:', users);
return users;
} catch (error) {
console.error('查询失败:', error);
throw error;
}
}
// 条件查询
async function queryActiveUsers() {
const response = await fetch(`${config.baseURL}/users?status=eq.active&order=created_at.desc`, {
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json'
}
});
return await response.json();
}
// 插入单条记录
async function createUser(userData) {
try {
const response = await fetch(`${config.baseURL}/users`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json',
'Prefer': 'return=representation' // 返回插入的数据
},
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('插入成功:', result);
return result;
} catch (error) {
console.error('插入失败:', error);
throw error;
}
}
// 批量插入
async function createUsers(usersData) {
const response = await fetch(`${config.baseURL}/users`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(usersData) // 传入数组
});
return await response.json();
}
// 更新数据
async function updateUser(userId, updateData) {
try {
const response = await fetch(`${config.baseURL}/users?id=eq.${userId}`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json',
'Prefer': 'return=representation'
},
body: JSON.stringify(updateData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('更新成功:', result);
return result;
} catch (error) {
console.error('更新失败:', error);
throw error;
}
}
// 批量更新
async function updateUsersByStatus(status, updateData) {
const response = await fetch(`${config.baseURL}/users?status=eq.${status}`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(updateData)
});
return await response.json();
}
// 删除数据
async function deleteUser(userId) {
try {
const response = await fetch(`${config.baseURL}/users?id=eq.${userId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
console.log('删除成功');
return true;
} catch (error) {
console.error('删除失败:', error);
throw error;
}
}
// 条件删除
async function deleteInactiveUsers() {
const response = await fetch(`${config.baseURL}/users?status=eq.inactive`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json'
}
});
return response.ok;
}
高级功能
- 计数查询
- 事务操作
- 错误处理
// 获取精确计数
async function getUserCount() {
const response = await fetch(`${config.baseURL}/users?select=*`, {
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Prefer': 'count=exact'
}
});
// 从响应头中获取计数
const count = response.headers.get('Content-Range');
console.log('用户总数:', count);
return count;
}
// HTTP API 不直接支持事务,需要通过 RPC 调用
async function transferPoints(fromUserId, toUserId, points) {
const response = await fetch(`${config.baseURL}/rpc/transfer_points`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
from_user: fromUserId,
to_user: toUserId,
point_amount: points
})
});
return await response.json();
}
// 统一错误处理
async function apiRequest(url, options = {}) {
try {
const response = await fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(`API Error: ${errorData.message || response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('API 请求失败:', error);
throw error;
}
}
// 使用示例
const users = await apiRequest(`${config.baseURL}/users?limit=10`);
查询参数说明
| 参数 | 说明 | 示例 |
|---|---|---|
select | 选择字段,支持关联查询 | select=id,name,categories(name) |
limit | 限制返回记录数 | limit=20 |
offset | 偏移量,用于分页 | offset=40 |
order | 排序字段 | order=created_at.desc |
字段名=操作符.值 | 过滤条件 | status=eq.active |
过滤操作符
| 操作符 | 说明 | 示例 |
|---|---|---|
eq | 等于 | status=eq.active |
neq | 不等于 | status=neq.inactive |
gt | 大于 | age=gt.18 |
gte | 大于等于 | age=gte.18 |
lt | 小于 | age=lt.65 |
lte | 小于等于 | age=lte.65 |
like | 模糊匹配 | name=like.*张* |
in | 包含 | id=in.(1,2,3) |
is | 空值检查 | email=is.null |
高级查询
查询修饰符
- 分页查询
- 排序查询
- 聚合查询
// 分页查询
const { data, error } = await db.from('articles')
.select('*')
.order('created_at', { ascending: false })
.range(0, 9); // 获取前 10 条记录
// 使用 limit 和 offset
const { data, error } = await db.from('articles')
.select('*')
.limit(10)
.offset(20);
// 单字段排序
const { data, error } = await db.from('articles')
.select('*')
.order('created_at', { ascending: false }); // 降序
// 多字段排序
const { data, error } = await db.from('articles')
.select('*')
.order('category_id', { ascending: true })
.order('created_at', { ascending: false });
// 计数查询
const { count, error } = await db.from('articles')
.select('*', { count: 'exact', head: true });
console.log('文章总数:', count);
// 分组计数
const { data, error } = await db.from('articles')
.select('category_id, count(*)')
.group('category_id');
复杂查询示例
// 复合条件查询
const { data, error } = await db.from('articles')
.select(`
id,
title,
category:categories(name),
author:users(name, email)
`)
.eq('status', 'published')
.gte('created_at', '2024-01-01')
.or('featured.eq.true,priority.gte.5')
.order('created_at', { ascending: false })
.limit(20);
// 内连接查询(排除 NULL 关联)
const { data, error } = await db.from('articles')
.select('title, categories!inner(name)')
.eq('categories.status', 'active');
事务处理
云开发 MySQL 支持事务操作,确保数据一致性:
exports.transferPoints = async (event, context) => {
const { fromUserId, toUserId, points } = event;
try {
// 开始事务
const { data, error } = await db.rpc('transfer_points', {
from_user: fromUserId,
to_user: toUserId,
point_amount: points
});
if (error) {
throw new Error(error.message);
}
return {
success: true,
message: '积分转移成功',
data: data
};
} catch (error) {
console.error('积分转移失败:', error);
return {
success: false,
error: error.message
};
}
};
原生 SQL 查询
对于复杂的查询需求,可以使用原生 SQL:
// 使用 RPC 调用存储过程或函数
const { data, error } = await db.rpc('get_user_statistics', {
user_id: 123,
start_date: '2024-01-01',
end_date: '2024-12-31'
});
// 复杂统计查询示例
const { data, error } = await db.rpc('complex_report', {
category: 'technology',
limit_count: 50
});
错误处理
exports.main = async (event, context) => {
try {
const { data, error } = await db.from('users')
.select('*')
.eq('id', event.userId);
if (error) {
// 处理数据库错误
console.error('数据库查询错误:', error);
return {
success: false,
error: '查询用户信息失败',
details: error.message
};
}
if (!data || data.length === 0) {
return {
success: false,
error: '用户不存在'
};
}
return {
success: true,
data: data[0]
};
} catch (error) {
console.error('系统错误:', error);
return {
success: false,
error: '系统内部错误'
};
}
};
最佳实践
1. 查询优化
// ✅ 好的做法:只查询需要的字段
const { data, error } = await db.from('users')
.select('id, name, email')
.eq('status', 'active');
// ❌ 避免:查询所有字段
const { data, error } = await db.from('users')
.select('*')
.eq('status', 'active');
2. 安全性
// ✅ 好的做法:使用参数化查询
const { data, error } = await db.from('users')
.select('*')
.eq('email', userEmail)
.eq('status', 'active');
// ✅ 数据验证
function validateUserInput(userData) {
if (!userData.email || !userData.email.includes('@')) {
throw new Error('无效的邮箱地址');
}
if (!userData.name || userData.name.length < 2) {
throw new Error('用户名至少需要2个字符');
}
}
3. 性能监控
// 查询性能监控
async function monitoredQuery(queryFunction) {
const startTime = Date.now();
try {
const result = await queryFunction();
const duration = Date.now() - startTime;
if (duration > 1000) {
console.warn(`慢查询检测: ${duration}ms`);
}
return result;
} catch (error) {
const duration = Date.now() - startTime;
console.error(`查询失败: ${duration}ms`, error);
throw error;
}
}
// 使用监控
const result = await monitoredQuery(() =>
db.from('articles').select('*').limit(100)
);
相关文档
🔗 Node.js SDK MySQL API - 查询数据
详细的查询数据 API 文档和示例
🔗 Node.js SDK MySQL API - 插入数据
插入数据的 API 文档和最佳实践
🔗 Node.js SDK MySQL API - 更新数据
更新数据的 API 文档和使用方法
🔗 Node.js SDK MySQL API - 删除数据
删除数据的 API 文档和安全注意事项
提示
- 所有的更新和删除操作都必须与过滤器结合使用,以防止误操作
- 建议在生产环境中对所有数据库操作进行错误处理
- 使用关联查询可以减少数据库请求次数,提高性能
- 定期监控查询性能,优化慢查询
注意
- 避免在循环中执行数据库查询,考虑使用批量操作
- 大数据量查询时注意使用分页,避免内存溢出
- 生产环境中务必对用户输入进行验证和过滤
安全提醒
- 始终使用参数化查询,避免 SQL 注入风险
- 不要在客户端代码中暴露数据库连接信息
- 遵循最小权限原则,只授予必要的数据库权限