TCB MySQL Database
TCB MySQL Database provides a fully managed relational database service that supports efficient data operations in cloud functions. This document details how to use MySQL database in cloud functions, including core features such as connection configuration, data operations, and transaction processing.
Quick Start
📄️ database connection
Learn how to connect to a MySQL database in cloud functions
📄️ Basic Operations
Master basic database operations such as CRUD
📄️ Advanced Queries
Advanced features such as join queries and aggregation queries
📄️ Best Practices
Best practices such as performance optimization and error handling
Database Connection
Initialize the SDK
Before using the MySQL database, you need to initialize the TCB SDK and obtain the database reference:
- Basic Connection
- Specify Instance
- In Cloud Functions
const cloudbase = require('@cloudbase/node-sdk');
// Initialize the TCB App instance
const app = cloudbase.init({
env: 'your-env-id' // Replace with your Environment ID
});
// Obtain the MySQL database reference (using the default instance and database)
const db = app.rdb();
const cloudbase = require('@cloudbase/node-sdk');
const app = cloudbase.init({
env: 'your-env-id'
});
// Specify a specific instance and database
const db = app.rdb({
instance: 'your-instance-name',
database: 'your-database-name'
});
// Cloud function entry file
const cloudbase = require('@cloudbase/node-sdk');
const app = cloudbase.init({
env: cloudbase.SYMBOL_CURRENT_ENV // Use the current environment
});
const db = app.rdb();
exports.main = async (event, context) => {
try {
// Use database operations here
const { data, error } = await db.from('users').select();
return {
success: true,
data: data
};
} catch (error) {
console.error('Database operation failed:', error);
return {
success: false,
error: error.message
};
}
};
Basic Operations
Querying Data
Use the select() method to query table data, which supports features such as conditional filtering and join queries.
- Basic Query
- Conditional Query
- Join Query
// Query all data.
const { data, error } = await db.from('articles').select();
// Query specified fields.
const { data, error } = await db.from('articles').select('id, title, created_at');
// Use * to query all fields.
const { data, error } = await db.from('articles').select('*');
console.log('Query result:', data);
// Equality Query
const { data, error } = await db.from('articles')
.select('*')
.eq('status', 'published');
// Range Query.
const { data, error } = await db.from('articles')
.select('id, title')
.gt('created_at', '2024-01-01')
.lt('created_at', '2024-12-31');
// Containment Query
const { data, error } = await db.from('articles')
.select('*')
.in('category_id', [1, 2, 3]);
// Fuzzy Query
const { data, error } = await db.from('articles')
.select('*')
.like('title', '%TCB%');
// Basic Join Query
const { data, error } = await db.from('articles').select(`
id,
title,
categories(name)
`);
// Using Aliases
const { data, error } = await db.from('articles').select(`
id,
title,
category:categories(name)
`);
// Multiple Joins (requires using foreign key constraint names to distinguish)
const { data, error } = await db.from('articles').select(`
title,
creator:users!articles_created_by_fkey(name),
updater:users!articles_updated_by_fkey(name)
`);
// Nested Join
const { data, error } = await db.from('categories').select(`
name,
articles (
title,
users (name)
)
`);
Inserting Data
Use the insert() method to insert data into a table, supporting single-row insertion and batch insertion.
- Single Insert
- Batch Insert
- Insert and Return
// Insert a single record
const { error } = await db.from('articles').insert({
title: 'TCB Getting Started Guide',
content: 'This is an introductory article about TCB...',
author_id: 1,
status: 'draft'
});
if (error) {
console.error('Insertion failed:', error);
} else {
console.log('Insertion succeeded');
}
// Batch insert multiple records
const { error } = await db.from('articles').insert([
{
title: 'First Article',
content: 'First Article Content',
author_id: 1
},
{
title: 'Second Article',
content: 'Second Article Content',
author_id: 2
}
]);
console.log('Batch insertion result:', error ? 'failed' : 'succeeded');
// Insert data and return the result (only valid when the table has a single auto-increment primary key)
const { data, error } = await db.from('articles').insert({
title: 'New Article Title',
content: 'Article Content'
}).select();
console.log('Inserted data:', data);
Updating Data
Use the update() method to update data in the table. Note: It must be used in conjunction with a filter.
- Single Update
- Batch Update
- Conditional Update
// Update the record with the specified ID
const { error } = await db.from('articles')
.update({
title: 'Updated Title',
status: 'published',
updated_at: new Date().toISOString()
})
.eq('id', 1);
console.log('Update result:', error ? 'Failed' : 'Succeeded');
// Batch update records that meet the criteria
const { error } = await db.from('articles')
.update({
status: 'published'
})
.eq('status', 'draft')
.gt('created_at', '2024-01-01');
console.log('Batch update result:', error ? 'Failed' : 'Succeeded');
// Update using multiple conditions
const { error } = await db.from('users')
.update({
last_login: new Date().toISOString(),
login_count: db.raw('login_count + 1') // Using a raw SQL expression
})
.eq('email', 'user@example.com')
.eq('status', 'active');
Delete data
Use the delete() method to delete data in the table. Note: It must be used in conjunction with a filter.
- Single Delete
- Batch Delete
- Conditional Delete
// Delete the record with the specified ID
const { error } = await db.from('articles')
.delete()
.eq('id', 1);
console.log('Delete result:', error ? 'Failed' : 'Succeeded');
// Batch delete multiple records
const { error } = await db.from('articles')
.delete()
.in('id', [1, 2, 3]);
console.log('Batch deletion result:', error ? 'Failed' : 'Succeeded');
// Delete the records that meet the conditions
const { error } = await db.from('articles')
.delete()
.eq('status', 'draft')
.lt('created_at', '2024-01-01');
console.log('Conditional delete result:', error ? 'Failed' : 'Succeeded');
HTTP API Access
Besides the Node.js SDK, you can also directly access the MySQL database via the HTTP API. The HTTP API follows the REST specification and supports standard HTTP methods for data operations.
Basic Configuration
- Authentication Configuration
- Environment Variables
// HTTP API requests must include authentication information
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-access-token',
// or use other authentication methods
'X-CloudBase-Credentials': 'your-credentials'
};
const baseURL = 'https://your-env-id.service.tcloudbase.com/v1/rdb/rest';
// recommend using environment variables to manage configurations
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
};
Querying Data
Use the GET method to query data in a table:
- Basic Query
- Filter Query
- Join Query
# Query all data
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"
# Querying specified fields
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?select=id,name,email" \
-H "Authorization: Bearer your-access-token"
# Pagination query
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?limit=10&offset=20" \
-H "Authorization: Bearer your-access-token"
# Equality Query
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?status=eq.active" \
-H "Authorization: Bearer your-access-token"
# Range Query
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"
# Fuzzy Query
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?name=like.*Zhang*" \
-H "Authorization: Bearer your-access-token"
# Sort Query
curl -X GET "https://your-env-id.service.tcloudbase.com/v1/rdb/rest/users?order=created_at.desc" \
-H "Authorization: Bearer your-access-token"
# Join Query
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"
# Multi-level Join
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"
# Using Aliases
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 Invocation Example
- Query Data
- Insert Data
- Update Data
- Delete Data
// Query user list
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('Query result:', users);
return users;
} catch (error) {
console.error('Query failed:', error);
throw error;
}
}
// Conditional Query
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();
}
// Insert a single record
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' // Return the inserted data
},
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('Insertion succeeded:', result);
return result;
} catch (error) {
console.error('Insertion failed:', error);
throw error;
}
}
// Batch insertion
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) // Pass in an array
});
return await response.json();
}
// Update data
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('Update succeeded:', result);
return result;
} catch (error) {
console.error('Update failed:', error);
throw error;
}
}
// Batch update
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();
}
// Delete data.
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('Delete succeeded');
return true;
} catch (error) {
console.error('Delete failed:', error);
throw error;
}
}
// Conditional delete
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;
}
Advanced Features
- Count Query
- Transaction Operations
- Error Handling
// Obtain exact count.
async function getUserCount() {
const response = await fetch(`${config.baseURL}/users?select=*`, {
headers: {
'Authorization': `Bearer ${config.accessToken}`,
'Prefer': 'count=exact'
}
});
// Obtain the count from the response headers.
const count = response.headers.get('Content-Range');
console.log('Total users:', count);
return count;
}
// HTTP API does not directly support transactions; RPC calls are required.
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();
}
// Unified Error Handling
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 request failed:', error);
throw error;
}
}
// Usage example
const users = await apiRequest(`${config.baseURL}/users?limit=10`);
Query Parameters Description
| Parameter | Description | Example |
|---|---|---|
select | Select fields, supports join queries | select=id,name,categories(name) |
limit | Limit the number of returned records | limit=20 |
offset | Offset for pagination | offset=40 |
order | Sort field | order=created_at.desc |
field_name=operator.value | Filter conditions | status=eq.active |
Filter Operators
| Operator | Description | Example |
|---|---|---|
eq | Equal to | status=eq.active |
neq | Not equal to | status=neq.inactive |
gt | Greater than | age=gt.18 |
gte | Greater than or equal to | age=gte.18 |
lt | Less than | age=lt.65 |
lte | Less than or equal to | age=lte.65 |
like | Pattern matching | name=like.*John* |
in | Is in | id=in.(1,2,3) |
is | Null check | email=is.null |
Advanced Query
Query Modifiers
- Pagination Query
- Sorting Query
- Aggregation Query
// Pagination
const { data, error } = await db.from('articles')
.select('*')
.order('created_at', { ascending: false })
.range(0, 9); // Retrieve the first 10 records
// Use limit and offset
const { data, error } = await db.from('articles')
.select('*')
.limit(10)
.offset(20);
// Single-field sorting
const { data, error } = await db.from('articles')
.select('*')
.order('created_at', { ascending: false }); // Descending
// Multi-field sorting
const { data, error } = await db.from('articles')
.select('*')
.order('category_id', { ascending: true })
.order('created_at', { ascending: false });
// Count Query
const { count, error } = await db.from('articles')
.select('*', { count: 'exact', head: true });
console.log('Total articles:', count);
// Grouped Count
const { data, error } = await db.from('articles')
.select('category_id, count(*)')
.group('category_id');
Complex Query Example
// Compound condition query
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);
// Inner Join Query (excluding NULL associations)
const { data, error } = await db.from('articles')
.select('title, categories!inner(name)')
.eq('categories.status', 'active');
Transaction Processing
TCB MySQL supports transaction operations, ensuring data consistency:
exports.transferPoints = async (event, context) => {
const { fromUserId, toUserId, points } = event;
try {
// Start the transaction.
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: 'Points transfer successful',
data: data
};
} catch (error) {
console.error('Points transfer failed:', error);
return {
success: false,
error: error.message
};
}
};
Native SQL Query
For complex query requirements, you can use native SQL:
// Use RPC to call stored procedures or functions
const { data, error } = await db.rpc('get_user_statistics', {
user_id: 123,
start_date: '2024-01-01',
end_date: '2024-12-31'
});
// Complex Statistical Query Example
const { data, error } = await db.rpc('complex_report', {
category: 'technology',
limit_count: 50
});
Error Handling
exports.main = async (event, context) => {
try {
const { data, error } = await db.from('users')
.select('*')
.eq('id', event.userId);
if (error) {
// Handle database errors
console.error('Database query error:', error);
return {
success: false,
error: 'Failed to query user information',
details: error.message
};
}
if (!data || data.length === 0) {
return {
success: false,
error: 'User does not exist'
};
}
return {
success: true,
data: data[0]
};
} catch (error) {
console.error('System error:', error);
return {
success: false,
error: 'Internal system error'
};
}
};
Best Practices
1. Query Optimization
// ✅ Good practice: Query only the required fields
const { data, error } = await db.from('users')
.select('id, name, email')
.eq('status', 'active');
// ❌ Avoid: querying all fields
const { data, error } = await db.from('users')
.select('*')
.eq('status', 'active');
2. Security
// ✅ Good practice: Use parameterized queries
const { data, error } = await db.from('users')
.select('*')
.eq('email', userEmail)
.eq('status', 'active');
// ✅ Data Validation
function validateUserInput(userData) {
if (!userData.email || !userData.email.includes('@')) {
throw new Error('Invalid email address');
}
if (!userData.name || userData.name.length < 2) {
throw new Error('Username must be at least 2 characters');
}
}
3. Performance Monitoring
// Query performance monitoring
async function monitoredQuery(queryFunction) {
const startTime = Date.now();
try {
const result = await queryFunction();
const duration = Date.now() - startTime;
if (duration > 1000) {
console.warn(`Slow query detected: ${duration}ms`);
}
return result;
} catch (error) {
const duration = Date.now() - startTime;
console.error(`Query failed: ${duration}ms`, error);
throw error;
}
}
// Using monitoring
const result = await monitoredQuery(() =>
db.from('articles').select('*').limit(100)
);
Related Documentation
🔗 Node.js SDK MySQL API - Query Data
Detailed query data API documentation and samples
🔗 Node.js SDK MySQL API - Insert Data
API documentation and best practices for inserting data
🔗 Node.js SDK MySQL API - Update Data
API documentation and usage for updating data
🔗 Node.js SDK MySQL API - Delete Data
API documentation and security considerations for deleting data
- All update and delete operations must be used in conjunction with a filter to prevent accidental operations
- It is recommended to implement error handling for all database operations in the production environment
- Using JOIN queries can reduce the number of database requests and improve performance
- Regularly monitor query performance and optimize slow queries
- Avoid executing database queries in loops; consider using batch operations
- Use pagination for large data volume queries to avoid memory overflow
- Always validate and filter user input in production environments
- Always use parameterized queries to prevent SQL injection risks
- Avoid exposing database connection information in client-side code
- Adhere to the principle of least privilege by granting only necessary database permissions