上一篇 Serverless 入门(六)- DynamoDB 数据库 介绍了为数据库创建一个表的整个过程,现在我们就来介绍如何更全面的操作数据库,包含:删除表、查询记录、修改记录,新增记录,删除记录。
1. 删除数据表
export const dropTable = {
TableName: 'Movies',
};
import { createTable, dropTable
} from "./models/movie";
export const drop: APIGatewayProxyHandler = async (event) => {
const dynamodb = getDynamoClient(event);
try {
const { TableDescription = {} } = await dynamodb.deleteTable(dropTable).promise();
return {
body: JSON.stringify({
creationDateTime: TableDescription.CreationDateTime,
tableStatus: TableDescription.TableStatus,
tableName: TableDescription.TableName,
message: 'Table drop successfully!',
}),
statusCode: 200,
};
} catch (e) {
return {
body: JSON.stringify(e),
statusCode: 500,
};
}
};
打开 serverless.yml
文件,在 createTable
同级下,新增如下配置:
dropTable:
handler: src/table.drop
events:
- http:
method: get
path: drop
虽然我们的服务命令中 「sls offline --useSeparateProcesses
」 使用了热加载,不针对 serverless.yml 配置,所以得重新执行一次上述命令。
2. 创建数据表
- 编写如下建表描述语句:AttributeDefinitions 表示定义「字段」,KeySchema 表示定义「主键」, ProvisionedThroughput 表示定义「吞吐量」
export const createTable = {
AttributeDefinitions: [
// 主键数据类型
{ AttributeName: 'year', AttributeType: 'N' }, // N Number
{ AttributeName: 'title', AttributeType: 'S' }, // S String
],
KeySchema: [
// 主键
{ AttributeName: 'year', KeyType: 'HASH' }, // Partition key 分区键
{ AttributeName: 'title', KeyType: 'RANGE' }, // Sort key 排序键
],
ProvisionedThroughput: {
// DynamoDB 预分配的吞吐量
ReadCapacityUnits: 20,
WriteCapacityUnits: 20,
},
TableName: 'Movies', // 表名
};
- 建表方法,代码如下:
export const create: APIGatewayProxyHandler = async event => {
const dynamodb = dynamoDBClient(event);
try {
const { TableDescription = {} } = await dynamodb.createTable(createTable).promise();
return {
body: JSON.stringify({
creationDateTime: TableDescription.CreationDateTime,
tableStatus: TableDescription.TableStatus,
tableName: TableDescription.TableName,
message: `Create table successfully!`,
}),
statusCode: 200,
};
} catch (e) {
return {
body: JSON.stringify(e),
statusCode: 500,
};
}
};
- 配置
serverless.yml
函数
# 创建表
createTable:
# table.ts 文件放到 src 里了,所以要加 src
handler: src/table.create
events:
- http:
method: get
path: create
- 执行成功后,会有如下提示:
{
creationDateTime: "2019-03-21T09:26:10.349Z",
tableStatus: "ACTIVE",
tableName: "Movies",
message: "Table create successfully!"
}
3. 新增记录
新增表记录时,就有一点不同了,我们换成使用dynamoDBDocumentClient
来操作DynamoDB 了。
export const saveData: APIGatewayProxyHandler = async event => {
const params = {
TableName: 'Movies',
Item: {
year: 2015,
title: 'The Big New Movie',
info: {
plot: 'Nothing happens at all.',
rating: 0,
},
},
};
try {
const dynamodbDoc = dynamoDBDocumentClient(event);
const result = await dynamodbDoc.put(params).promise();
return {
body: JSON.stringify({ ...result, message: `Table save data successfully!` }),
statusCode: 200,
};
} catch (e) {
return getExceptionBody(e);
}
};
dynamoDBDocumentClient
的代码只是在 DynamoDB里的对象里实例化一个 DocumentClient 对象,如下所示:
export const dynamoDBDocumentClient = (event, port = 8000, region = 'localhost') => {
if ('isOffline' in event && event.isOffline) {
return new DynamoDB.DocumentClient({ endpoint: `http://localhost:${port}`, region });
}
return new DynamoDB.DocumentClient();
};
4. 查询记录
在 DynamoDB 里查询记录可以简单分为如下三种:
- get 获取某一条记录
const params = { TableName: 'Movies', Key: { year: 2013, title: 'Rush' } };
const result = await dynamodbDoc.get(params).promise();
- query 获取指定条件的记录
const params = {
TableName: 'Movies',
KeyConditionExpression: '#year=:yyyy',
ExpressionAttributeNames: { '#year': 'year' },
ExpressionAttributeValues: { ':yyyy': 1993 },
};
const result = await dynamodbDoc.query(params).promise();
- scan 获取大量的记录
const params = {
TableName: 'Movies',
// 只查询如下 3 个「字段」
ProjectionExpression: '#year, title, info.rating',
// 过虑器表达式
FilterExpression: '#year between :start and :end',
ExpressionAttributeNames: { '#year': 'year' },
ExpressionAttributeValues: { ':start': 1993, ':end': 2019 },
};
const result = await dynamodbDoc.scan(params).promise();
5. 修改记录
先指定表名、主键名,然后配置更新表达式及对应的值,如代码所示:
const params = {
TableName: 'Movies',
Key: { year: 2015, title: 'The Big New Movie' },
UpdateExpression: 'set info.rating=:r, info.plot=:p, info.actors=:a',
ExpressionAttributeValues: {
':r': 5.5,
':p': 'Everything happens all at once.',
':a': ['Larry', 'Moe', 'Curly'],
},
// ReturnValues 有如下几种:NONE, ALL_OLD, UPDATED_OLD, ALL_NEW, UPDATED_NEW
ReturnValues: 'UPDATED_NEW',
};
const result = await dynamodbDoc.update(params).promise();
这种用表达式的方式修改数据,有效的解决了 SQL 注入的问题,安心!
6. 删除记录
删除记录跟上面的代码与套路相似,我就直接列出代码片段:
const params = {
TableName: 'Movies',
Key: { year: 2015, title: 'The Big New Movie' },
ConditionExpression: 'info.rating >= :value',
ExpressionAttributeValues: { ':value': 5.0 },
};
const result = await dynamodbDoc.delete(params).promise();
7. 项目源代码
由于篇幅原因,上面的代码我只贴出了片段,下面链接是代码详情:
https://github.com/Kennytian/learning-serverless
8. 好消息
- 上篇文章里介绍的「Dynamon」工具,打开大数量的表时会 crash。所以我又找到了另一位作者开发的版本,其兼容性与 UI 美观程序会更胜一筹,项目地址 https://github.com/deptno/dynamon ,UI 如图所示:
相关文章
- Serverless 入门(一) - 创建 IAM https://www.jianshu.com/p/9fb731a799e2
- Serverless 入门(二) - HelloWord https://www.jianshu.com/p/ddf2ffda5f63
- Serverless 入门(三)- 初始项目解读 https://www.jianshu.com/p/8baba2a8fe9f
- Serverless 入门(四)- 如何调试 https://www.jianshu.com/p/58d30915de8a
- Serverless 入门(五)- 常用命令 https://www.jianshu.com/p/28f001ea9d9d
- Serverless 入门(六)- DynamoDB 数据库(上) https://www.jianshu.com/p/c313b61d1cbf
- Serverless 入门(七)- DynamoDB 数据库(中) https://www.jianshu.com/p/05e7f4ccd6fe
- Serverless 入门(八)- DynamoDB 数据库(下) https://www.jianshu.com/p/0f9f1561ec46
- Serverless 入门(九)- 权限 https://www.jianshu.com/p/97228749d761