欢迎来到鸿蒙端云一体化开发教程的第二篇。上一篇我们学习了云函数,今天咱们来攻克另一个核心功能------云数据库。
在开发应用时,数据存储是绕不开的话题。传统开发需要自己搭建数据库服务器、设计表结构、编写SQL语句,还得操心数据库的备份、扩容和安全问题。Cloud Foundation Kit的云数据库服务把这些麻烦事都解决了。它提供了一个端云协同的数据库,你可以在客户端直接对数据进行增删改查,而且支持数据实时同步,非常适合开发需要跨设备同步数据的应用。
一、实战场景:图书管理系统
为了让大家更好地理解,我们今天通过开发一个简单的"图书管理系统"来学习云数据库的使用。我们需要实现以下功能:
- 录入新书信息(写入数据)
- 查询书籍列表(查询数据)
- 借阅书籍(更新数据)
- 图书遗失处理(删除数据)
二、在AGC控制台配置数据库
在写代码之前,我们需要先在云端把"地基"打好。
2.1 新增对象类型
云数据库使用"对象类型"来定义数据结构,有点像传统数据库里的"表"。
-
登录AppGallery Connect,进入"云开发 > 云数据库"页面。
-
点击"新增",创建一个名为
BookInfo的对象类型。


-
添加以下字段:
| 字段名称 | 类型 | 主键 | 非空 | 说明 |
|---|---|---|---|---|
| id | Integer | ✓ | ✓ | 图书ID |
| bookName | String | - | ✓ | 书名 |
| author | String | - | - | 作者 |
| price | Double | - | - | 价格 |
| borrowerId | Integer | - | - | 借阅人ID |
| borrowerName | String | - | - | 借阅人姓名 |
| borrowerTime | Date | - | - | 借阅时间 |
-
添加索引:点击"新增索引",设置索引名为
bookName,这样按书名查询会更快。

-
设置权限:为了演示方便,我们将"所有人"、"认证用户"、"数据创建者"、"管理员"的权限(query, upsert, delete)都勾选上。注意:实际项目中,为了安全起见,建议根据业务严格限制"所有人"的权限。
2.2 导出并引入对象类型文件
配置好后,我们需要把这个定义导出给代码使用。
-
在对象类型列表中勾选
BookInfo,点击"导出"。

-
选择"json格式",下载得到一个文件。
-
将文件重命名为
schema.json。

-
在你的DevEco Studio项目中,将该文件拷贝到
AppScope/resources/rawfile或者entry/src/main/resources/rawfile目录下。
2.3 新增存储区
存储区就是存放数据的地方,相当于一个具体的数据库实例。
- 在云数据库页面点击"存储区"页签。

- 点击"新增",输入名称
QuickStartDemo,点击确定。

三、代码实现
地基打好了,现在开始盖楼!
3.1 创建数据对象类
我们需要在ArkTS代码中创建一个类来对应云端的BookInfo。新建BookInfo.ets文件:
typescript
import { cloudDatabase } from '@kit.CloudFoundationKit';
class BookInfo extends cloudDatabase.DatabaseObject {
public naturalbase_ClassName(): string {
return "BookInfo";
}
public id: number | undefined;
public bookName: string | undefined;
public author: string | undefined;
public price: number | undefined;
public borrowerId: number | undefined;
public borrowerName: string | undefined;
public borrowerTime: Date | undefined;
}
export { BookInfo };
3.2 初始化云数据库
在使用数据库之前,需要进行初始化。通常我们会在应用启动或者页面加载时做这件事。
首先,别忘了申请网络权限。在entry/src/main/module.json5中添加:
json
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
然后,初始化数据库区域(DatabaseZone):
typescript
import { cloudDatabase } from '@kit.CloudFoundationKit';
import { BookInfo } from './BookInfo'; // 引入刚才定义的类
// 使用我们在控制台创建的存储区名称 'QuickStartDemo'
let databaseZone = cloudDatabase.zone('QuickStartDemo');
// 创建查询条件对象,后续查询都要用到它
let condition = new cloudDatabase.DatabaseQuery(BookInfo);
3.3 写入数据(新增/修改)
云数据库提供了一个非常方便的方法叫upsert(更新插入)。如果数据不存在(主键ID不同),它就新增;如果数据已存在(主键ID相同),它就更新。
场景一:录入新书
typescript
import { hilog } from '@kit.PerformanceAnalysisKit';
async function addBook() {
try {
let book = new BookInfo();
book.id = 1;
book.bookName = "鸿蒙开发实战";
book.author = "张三";
book.price = 59.9;
// 写入数据
let record = await databaseZone.upsert(book);
hilog.info(0x0000, 'testTag', `成功录入书籍: ${JSON.stringify(record)}`);
} catch (err) {
hilog.error(0x0000, 'testTag', `录入失败: ${err.code}, ${err.message}`);
}
}
场景二:借阅书籍(更新数据)
借书其实就是更新书籍的借阅人信息。
typescript
async function borrowBook() {
try {
// 假设我们要借阅《鸿蒙开发实战》
// 先查询这本书(这里简化逻辑,假设已知ID为1)
let book = new BookInfo();
book.id = 1;
book.bookName = "鸿蒙开发实战"; // upsert需要主键,其他字段如果要更新也需要赋值
book.borrowerId = 1001;
book.borrowerName = "李四";
book.borrowerTime = new Date();
// 再次调用upsert,因为ID已存在,会执行更新操作
let record = await databaseZone.upsert(book);
hilog.info(0x0000, 'testTag', `借阅成功: ${JSON.stringify(record)}`);
} catch (err) {
hilog.error(0x0000, 'testTag', `借阅失败: ${err.code}, ${err.message}`);
}
}
3.4 查询数据
查询是数据库最常用的功能。云数据库提供了非常丰富的查询能力。
场景三:查询所有书籍
typescript
async function queryAllBooks() {
try {
// 空的condition表示无过滤条件,查询所有
let resultArray = await databaseZone.query(condition);
hilog.info(0x0000, 'testTag', `查询到 ${resultArray.length} 本书`);
} catch (err) {
hilog.error(0x0000, 'testTag', `查询失败: ${err.code}, ${err.message}`);
}
}
场景四:按条件查询(复合查询)
比如我们要找"价格在20到50之间,且书名包含'数据库'"的书:
typescript
async function searchBooks() {
try {
condition.contains('bookName', '数据库')
.greaterThan('price', 20.0)
.and() // 多个条件默认是and,也可以显式调用
.lessThan('price', 50.0);
let resultArray = await databaseZone.query(condition);
hilog.info(0x0000, 'testTag', `符合条件的书籍: ${JSON.stringify(resultArray)}`);
} catch (err) {
hilog.error(0x0000, 'testTag', `查询失败: ${err.code}, ${err.message}`);
}
}
场景五:随机推荐(随机查询)
从6.0.1版本开始,支持随机查询,特别适合做"猜你喜欢"功能。
typescript
async function recommendBooks() {
try {
// 随机取出10本书
condition.orderByRandom().limit(10);
let resultArray = await databaseZone.query(condition);
hilog.info(0x0000, 'testTag', `推荐书籍: ${JSON.stringify(resultArray)}`);
} catch (err) {
hilog.error(0x0000, 'testTag', `推荐失败: ${err.code}, ${err.message}`);
}
}
3.5 删除数据
场景六:图书遗失处理
如果书丢了,需要从系统中删除。
typescript
async function deleteBook() {
try {
let book = new BookInfo();
book.id = 1; // 只需要设置主键即可
let deleteNum = await databaseZone.delete(book);
hilog.info(0x0000, 'testTag', `成功删除 ${deleteNum} 本书`);
} catch (err) {
hilog.error(0x0000, 'testTag', `删除失败: ${err.code}, ${err.message}`);
}
}
四、进阶技巧
4.1 数据排序与分页
当数据量很大时,我们通常需要分页显示。
typescript
async function queryByPage() {
// 查询价格小于50的书,按价格降序排列
// limit(10, 6) 表示跳过前6条,取接下来的10条(即第2页,每页10条,从第7条开始取)
condition.lessThan('price', 50.0)
.orderByDesc('price')
.limit(10, 6);
let resultArray = await databaseZone.query(condition);
}
4.2 算术计算
如果你想知道所有书的平均价格,不需要把书都查出来再自己算,直接用calculateQuery:
typescript
async function getAveragePrice() {
try {
// 计算所有价格小于50的书的平均价
condition.lessThan('price', 50.0);
let resultNum = await databaseZone.calculateQuery(condition, 'price', cloudDatabase.QueryCalculate.AVERAGE);
hilog.info(0x0000, 'testTag', `平均价格: ${resultNum}`);
} catch (err) {
hilog.error(0x0000, 'testTag', `计算失败: ${err.code}, ${err.message}`);
}
}
五、注意事项
- 存储区限制:一个应用最多创建4个存储区,多了会报错。一般情况下一个就够用了。
- 批量操作限制:写入或删除一组对象时,单次不能超过1000条,总大小不能超过2MB。
- 查询对象 :
databaseZone和condition对象在每次查询中建议独立使用或重置,避免上一次的查询条件影响下一次。 - 数据一致性 :
upsert和delete操作是原子性的,要么全成功,要么全失败,这保证了数据的一致性。 - 权限控制:在AGC控制台配置权限时要格外小心,正式上线前一定要检查"所有人"角色的权限,防止数据泄露。
六、总结
至此,我们掌握了云数据库的核心用法:
云数据库极大地简化了后端数据存储的开发工作,让你能更专注于前端业务逻辑的实现。下一篇教程,我们将学习如何使用云存储来管理图片、视频等大文件!