HarmonyOS 鸿蒙Next中KV数据库奇怪的bug
HarmonyOS 鸿蒙Next中KV数据库奇怪的bug
const KV_CONFIG: distributedKVStore.Options = {
autoSync: true,
securityLevel: distributedKVStore.SecurityLevel.S1
}
let old_kv_manager = distributedKVStore.createKVManager({
context: old_context, bundleName: Constant.BUNDLE_NAME
})
let new_kv_manager = distributedKVStore.createKVManager({
context: new_context, bundleName: Constant.BUNDLE_NAME
})
old_kv_manager.getAllKVStoreId(Constant.BUNDLE_NAME, (err, data) => {
console.log('old all: ', JSON.stringify(data))
})
new_kv_manager.getAllKVStoreId(Constant.BUNDLE_NAME, (err, data) => {
console.log('new all: ', JSON.stringify(data))
})
let old_kv_store = await old_kv_manager.getKVStore<distributedKVStore.DeviceKVStore>("Config", KV_CONFIG)
let new_kv_store = await new_kv_manager.getKVStore<distributedKVStore.DeviceKVStore>("Config", KV_CONFIG)
hilog.info(0x0000, 'RestoreOldContext', 'get old and new store')
await old_kv_store.put('A', 1)
old_kv_store.getResultSet(new distributedKVStore.Query(), (err, data) => {
while (data.moveToNext()) {
console.log('old: ', data.getEntry().key, JSON.stringify(data.getEntry().value))
}
})
new_kv_store.getResultSet(new distributedKVStore.Query(), (err, data) => {
while (data.moveToNext()) {
console.log('new: ', data.getEntry().key, JSON.stringify(data.getEntry().value))
}
})
上述代码中,old_context为UIAbilityContext,new_context为ApplicationContext,这两个context分别获取kvmanager,然后再区获取kvstore,实际上获取到的kvstore是同一个!!!日志证明:
01-17 13:43:35.421 52452-52452 A03D00/appspawn/JSAPP xxxx I new all: ["Config","Config"]
01-17 13:43:35.421 52452-52452 A03D00/appspawn/JSAPP xxxx I old all: ["Config","Config"]
01-17 13:43:35.443 52452-52452 A00000/appspaw...oreOldContext xxxx I get old and new store
01-17 13:43:35.460 52452-52452 A03D00/appspawn/JSAPP xxxx I old: A {"type":5,"value":1}
01-17 13:43:35.460 52452-52452 A03D00/appspawn/JSAPP com.onecourse.next I old: privacy_viewed {"type":0,"value":"true"}
01-17 13:43:35.460 52452-52452 A03D00/appspawn/JSAPP xxxx I old: restore_db {"type":4,"value":true}
01-17 13:43:35.460 52452-52452 A03D00/appspawn/JSAPP xxxx I old: showing_course_id {"type":5,"value":17680248227663744}
01-17 13:43:35.461 52452-52452 A03D00/appspawn/JSAPP xxxx I new: A {"type":5,"value":1}
01-17 13:43:35.461 52452-52452 A03D00/appspawn/JSAPP xxxx I new: privacy_viewed {"type":0,"value":"true"}
01-17 13:43:35.461 52452-52452 A03D00/appspawn/JSAPP xxxx I new: restore_db {"type":4,"value":true}
01-17 13:43:35.461 52452-52452 A03D00/appspawn/JSAPP xxxx I new: showing_course_id {"type":5,"value":17680248227663744}
这里的A成员之前是没有的,我只在oldstore进行了put动作,但是实际newstore也能查出来。所以这个context是没有用的吗?
实际上也不是的,当我删除所有old的代码,只通过ApplicationContext获取kvmanager然后获取kvstore,这时候获取到的kvstore是全新的,没有任何数据。
麻烦官方定位解释一下!
更多关于HarmonyOS 鸿蒙Next中KV数据库奇怪的bug的实战教程也可以访问 https://www.itying.com/category-93-b0.html
【解决方案】
开发者您好,本地使用您提供的代码未复现出问题,测试结果是old_kv_store和new_kv_store是两个不同的对象。不运行old_kv_store相关代码后查询结果为空是因为没有添加数据,新增下面语句后可以打印日志。
await new_kv_store.put('A', 1)
如果未能解决问题,请提供以下信息:
1.当前开发工具版本(Help->About DevEco Studio)、运行时API版本(File->Project Structure->Project->Basic Info->Compatible SDK)、手机系统版本信息 (设置->关于手机)
完整复现代码:
async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
const BUNDLE_NAME = 'BUNDLE_NAME';
const KV_CONFIG: distributedKVStore.Options = {
autoSync: true,
securityLevel: distributedKVStore.SecurityLevel.S1
}
let old_kv_manager = distributedKVStore.createKVManager({
context: this.context, bundleName: BUNDLE_NAME
})
let new_kv_manager = distributedKVStore.createKVManager({
context: this.context.getApplicationContext(), bundleName: BUNDLE_NAME
})
old_kv_manager.getAllKVStoreId(BUNDLE_NAME, (err, data) => {
console.log('old all: ', JSON.stringify(data))
})
new_kv_manager.getAllKVStoreId(BUNDLE_NAME, (err, data) => {
console.log('new all: ', JSON.stringify(data))
})
let old_kv_store = await old_kv_manager.getKVStore<distributedKVStore.DeviceKVStore>("Config", KV_CONFIG)
let new_kv_store = await new_kv_manager.getKVStore<distributedKVStore.DeviceKVStore>("Config", KV_CONFIG)
hilog.info(0x0000, 'RestoreOldContext', 'get old and new store')
await old_kv_store.put('A', 1)
await new_kv_store.put('A', 1)
old_kv_store.getResultSet(new distributedKVStore.Query(), (err, data) => {
while (data.moveToNext()) {
console.log('old: ', data.getEntry().key, JSON.stringify(data.getEntry().value))
}
})
new_kv_store.getResultSet(new distributedKVStore.Query(), (err, data) => {
while (data.moveToNext()) {
console.log('new: ', data.getEntry().key, JSON.stringify(data.getEntry().value))
}
})
}
更多关于HarmonyOS 鸿蒙Next中KV数据库奇怪的bug的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
let old_kv_manager = distributedKVStore.createKVManager({
context: old_context, bundleName: Constant.BUNDLE_NAME
})
let new_kv_manager = distributedKVStore.createKVManager({
context: new_context, bundleName: Constant.BUNDLE_NAME
})
这里创建的都是同一个数据库实例,只是不同引用,所以你操作old,new也会同步变化,而且你使用的options和storeId都是一样的,至于你所说的删除了所有old代码,因没看到你的具体删除代码,猜测是指删库行为,你用new再去获取相当于重新申请创建数据库并分配一个新的ID值。
解释如下:
ApplicationContext跟UIAbilityContext实际上都是继承于Context,而BaseContext是所有Context类型的父类,所以你用上面两个的Context获取数据库实例,最终用的还是同一个,至于数据库的唯一性取决于你配置的options与storeId。




相关文档:
我说的删除代码是指不执行old的那行getkvstore,
IDE版本是多少?运行设备的API版本是多少?我这边打印是只有一个config。
- 你的代码中两个
KVManager使用了相同的: bundleName: Constant.BUNDLE_NAMEstoreId: "Config"securityLevel: S1因此系统会返回同一个物理存储实例,无论使用UIAbilityContext还是ApplicationContext。KVStore 的「物理唯一标识」不是Context,而是bundleName + storeId + securityLevel
可以通过不同storeId隔离存储空间。
// 修改storeId实现隔离
let old_store = await old_kv_manager.getKVStore<distributedKVStore.DeviceKVStore>("OldConfig", KV_CONFIG);
let new_store = await new_kv_manager.getKVStore<distributedKVStore.DeviceKVStore>("NewConfig", KV_CONFIG);
不理解啊,如果是唯一标识,怎么能创建出来两个呢,
不是,你的问题不是创建了2个结果是1个吗?因为你创建虽然用过来不同的Context,但是bundleName + storeId + securityLevel,这3个都一样,所以创建的2个其实还是一个,现在用不同的storeId的方法创建不同的2个。
不是的,你看getallstoreid查出来的,真的有两个,
这个是不同的CONTEXT有不同的存储分区。
官网原文:应用创建的数据库与其上下文(Context)有关,即使使用同样的数据库名称,但不同的应用上下文,会产生多个数据库,例如每个UIAbility都有各自的上下文。
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/data-persistence-by-rdb-store#开发步骤
建议了解下context文档
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/app-sandbox-directory#应用文件目录与应用文件路径
数据库调试文档
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/vector-store-debug-tool
你仔细看一下我发的内容,我也以为是不同context不同数据库,但是数据获取到的是一个,
UIAbilityContext 和 ApplicationContext 在分布式 KV 里,不是“存储隔离维度”。
只要 bundleName + storeId + securityLevel 一样,
👉 不管你用哪个 Context,拿到的都是同一个物理 KVStore。
| Context | 是否推荐作为 KV 主要入口 | 原因 |
|---|---|---|
| UIAbilityContext | ✅ 强烈推荐 | 能保证数据已恢复完成 |
| ApplicationContext | ⚠️ 仅限特定场景 | 可能读到“未就绪数据” |
那如何解释我用kvmanager查询allstoreid返回了两个同名store的问题,
而且我如果删掉old的代码,直接使用application去获取kvstore,拿到的是一个新的数据库,里面什么都没有,
鸿蒙Next的KV数据库bug可能涉及数据读写异常、键值对丢失或并发访问冲突。具体表现包括数据持久化失败、查询结果不一致或应用崩溃。建议检查数据库初始化配置、数据操作逻辑及多线程同步机制。
根据您提供的代码和日志,这并非一个bug,而是HarmonyOS Next中分布式KV数据库的设计机制。
核心原因在于:对于同一个应用,通过不同Context创建的KVManager,如果指定了相同的bundleName和storeId,它们访问的是同一个物理KV数据库实例。
在您的场景中:
old_context(UIAbilityContext) 和new_context(ApplicationContext) 都属于同一个应用。- 您使用相同的
Constant.BUNDLE_NAME和"Config"作为参数来创建KVManager和获取KVStore。 - 因此,
old_kv_store和new_kv_store实际上是指向同一个底层数据库“Config”的两个句柄。通过任何一个句柄写入数据(如old_kv_store.put('A', 1)),另一个句柄自然能读取到。
日志分析:
getAllKVStoreId两次都输出了["Config","Config"],这进一步证实了对于同一个bundleName,两个KVManager管理的是同一组Store ID列表。- 查询日志显示,
old和new查询出的数据完全一致,包括您刚插入的'A':1,这符合上述设计。
关于您后续的测试现象:
当您删除所有old_context相关代码,仅使用ApplicationContext时,如果数据库“Config”之前从未被成功创建并持久化过,那么获取到的就是一个全新的空数据库。这并不能证明Context无效,反而说明了:
- 首次创建数据库时,需要成功完成
put等写入操作,数据才会被持久化。 - 只要数据库被成功创建并持久化,之后无论通过该应用下的哪个Context(UIAbilityContext或ApplicationContext),只要
bundleName和storeId相同,访问的都是同一个持久化的数据库。
结论:
distributedKVStore的设计是以应用(由bundleName标识)和数据库名(storeId)为维度进行隔离的,而不是以Context为维度。在同一个应用内,Context主要用于获取访问权限和资源路径,在访问同一持久化数据库时,它们的作用是等效的。您观察到的行为是符合预期的。


