1# 批量数据写数据库场景 2 3## 使用TaskPool进行频繁数据库操作 4 5对于需要频繁数据库操作的场景,由于读写数据库存在耗时,因此推荐在子线程中操作,避免阻塞UI线程。 6 7通过ArkTS提供的TaskPool能力,可以将数据库操作任务移到子线程中,实现如下。 8 91. 创建多个子任务,支持数据库创建、插入、查询、清除等操作。 10 112. UI主线程调用子任务完成增删改查等数据库操作。 12 13```ts 14// Index.ets 15import { relationalStore, ValuesBucket } from '@kit.ArkData'; 16import { taskpool } from '@kit.ArkTS'; 17 18@Concurrent 19async function create(context: Context) { 20 const CONFIG: relationalStore.StoreConfig = { 21 name: "Store.db", 22 securityLevel: relationalStore.SecurityLevel.S1, 23 }; 24 25 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 26 let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG); 27 console.info(`Create Store.db successfully!`); 28 29 // 创建表 30 const CREATE_TABLE_SQL = "CREATE TABLE IF NOT EXISTS test (" + 31 "id INTEGER PRIMARY KEY AUTOINCREMENT, " + 32 "name TEXT NOT NULL, " + 33 "age INTEGER, " + 34 "salary REAL, " + 35 "blobType BLOB)"; 36 await store.executeSql(CREATE_TABLE_SQL); 37 console.info(`Create table test successfully!`); 38} 39 40@Concurrent 41async function insert(context: Context, valueBucketArray: Array<relationalStore.ValuesBucket>) { 42 const CONFIG: relationalStore.StoreConfig = { 43 name: "Store.db", 44 securityLevel: relationalStore.SecurityLevel.S1, 45 }; 46 47 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 48 let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG); 49 console.info(`Create Store.db successfully!`); 50 51 // 数据插入 52 await store.batchInsert("test", valueBucketArray as Object as Array<relationalStore.ValuesBucket>); 53} 54 55@Concurrent 56async function query(context: Context): Promise<Array<relationalStore.ValuesBucket>> { 57 const CONFIG: relationalStore.StoreConfig = { 58 name: "Store.db", 59 securityLevel: relationalStore.SecurityLevel.S1, 60 }; 61 62 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 63 let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG); 64 console.info(`Create Store.db successfully!`); 65 66 // 获取结果集 67 let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates("test"); 68 let resultSet = await store.query(predicates); // 查询所有数据 69 console.info(`Query data successfully! row count:${resultSet.rowCount}`); 70 let index = 0; 71 let result = new Array<relationalStore.ValuesBucket>(resultSet.rowCount) 72 resultSet.goToFirstRow() 73 do { 74 result[index++] = resultSet.getRow() 75 } while (resultSet.goToNextRow()); 76 resultSet.close(); 77 return result 78} 79 80@Concurrent 81async function clear(context: Context) { 82 const CONFIG: relationalStore.StoreConfig = { 83 name: "Store.db", 84 securityLevel: relationalStore.SecurityLevel.S1, 85 }; 86 87 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 88 await relationalStore.deleteRdbStore(context, CONFIG); 89 console.info(`Delete Store.db successfully!`); 90} 91 92@Entry 93@Component 94struct Index { 95 @State message: string = 'Hello World'; 96 97 build() { 98 RelativeContainer() { 99 Text(this.message) 100 .id('HelloWorld') 101 .fontSize(50) 102 .fontWeight(FontWeight.Bold) 103 .alignRules({ 104 center: { anchor: '__container__', align: VerticalAlign.Center }, 105 middle: { anchor: '__container__', align: HorizontalAlign.Center } 106 }) 107 .onClick(async () => { 108 let context = getContext(this); 109 110 // 数据准备 111 const count = 5 112 let valueBucketArray = new Array<relationalStore.ValuesBucket>(count); 113 for (let i = 0; i < count; i++) { 114 let v : relationalStore.ValuesBucket = { 115 id: i, 116 name: "zhangsan" + i, 117 age: 20, 118 salary: 5000 + 50 * i 119 }; 120 valueBucketArray[i] = v; 121 } 122 await taskpool.execute(create, context) 123 await taskpool.execute(insert, context, valueBucketArray) 124 let index = 0 125 let ret = await taskpool.execute(query, context) as Array<relationalStore.ValuesBucket> 126 for (let v of ret) { 127 console.info(`Row[${index}].id = ${v.id}`) 128 console.info(`Row[${index}].name = ${v.name}`) 129 console.info(`Row[${index}].age = ${v.age}`) 130 console.info(`Row[${index}].salary = ${v.salary}`) 131 index++ 132 } 133 await taskpool.execute(clear, context) 134 }) 135 } 136 .height('100%') 137 .width('100%') 138 } 139} 140``` 141 142## 使用Sendable进行大容量数据库操作 143 144由于数据库数据跨线程传递存在耗时,当数据量较大时,仍然会占用UI主线程,推荐采用Sendable封装数据库数据,降低跨线程开销。 145 1461. 定义数据库中的数据格式,可采用Sendable,减少跨线程耗时。 147 148 ```ts 149 // SharedValuesBucket.ets 150 export interface IValueBucket { 151 id: number 152 name: string 153 age: number 154 salary: number 155 } 156 157 @Sendable 158 export class SharedValuesBucket implements IValueBucket { 159 id: number = 0 160 name: string = "" 161 age: number = 0 162 salary: number = 0 163 164 constructor(v: IValueBucket) { 165 this.id = v.id; 166 this.name = v.name; 167 this.age = v.age; 168 this.salary = v.salary 169 } 170 } 171 ``` 172 1732. UI主线程发起,在子线程进行数据的增删改查等操作。 174 175 ```ts 176 // Index.ets 177 import { relationalStore, ValuesBucket } from '@kit.ArkData'; 178 import { collections, taskpool } from '@kit.ArkTS'; 179 import { IValueBucket, SharedValuesBucket } from './SharedValuesBucket'; 180 181 @Concurrent 182 async function create(context: Context) { 183 const CONFIG: relationalStore.StoreConfig = { 184 name: "Store.db", 185 securityLevel: relationalStore.SecurityLevel.S1, 186 }; 187 188 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 189 let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG); 190 console.info(`Create Store.db successfully!`); 191 192 // 创建表 193 const CREATE_TABLE_SQL = "CREATE TABLE IF NOT EXISTS test (" + 194 "id INTEGER PRIMARY KEY AUTOINCREMENT, " + 195 "name TEXT NOT NULL, " + 196 "age INTEGER, " + 197 "salary REAL, " + 198 "blobType BLOB)"; 199 await store.executeSql(CREATE_TABLE_SQL); 200 console.info(`Create table test successfully!`); 201 } 202 203 @Concurrent 204 async function insert(context: Context, valueBucketArray: collections.Array<SharedValuesBucket | undefined>) { 205 const CONFIG: relationalStore.StoreConfig = { 206 name: "Store.db", 207 securityLevel: relationalStore.SecurityLevel.S1, 208 }; 209 210 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 211 let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG); 212 console.info(`Create Store.db successfully!`); 213 214 // 数据插入 215 await store.batchInsert("test", valueBucketArray as Object as Array<ValuesBucket>); 216 } 217 218 @Concurrent 219 async function query(context: Context): Promise<collections.Array<SharedValuesBucket | undefined>> { 220 const CONFIG: relationalStore.StoreConfig = { 221 name: "Store.db", 222 securityLevel: relationalStore.SecurityLevel.S1, 223 }; 224 225 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 226 let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG); 227 console.info(`Create Store.db successfully!`); 228 229 // 获取结果集 230 let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates("test"); 231 let resultSet = await store.query(predicates); // 查询所有数据 232 console.info(`Query data successfully! row count:${resultSet.rowCount}`); 233 let index = 0; 234 let result = collections.Array.create<SharedValuesBucket | undefined>(resultSet.rowCount, undefined) 235 resultSet.goToFirstRow() 236 do { 237 let v: IValueBucket = { 238 id: resultSet.getLong(resultSet.getColumnIndex("id")), 239 name: resultSet.getString(resultSet.getColumnIndex("name")), 240 age: resultSet.getLong(resultSet.getColumnIndex("age")), 241 salary: resultSet.getLong(resultSet.getColumnIndex("salary")) 242 }; 243 result[index++] = new SharedValuesBucket(v) 244 } while (resultSet.goToNextRow()); 245 resultSet.close(); 246 return result 247 } 248 249 @Concurrent 250 async function clear(context: Context) { 251 const CONFIG: relationalStore.StoreConfig = { 252 name: "Store.db", 253 securityLevel: relationalStore.SecurityLevel.S1, 254 }; 255 256 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 257 await relationalStore.deleteRdbStore(context, CONFIG); 258 console.info(`Delete Store.db successfully!`); 259 } 260 261 @Entry 262 @Component 263 struct Index { 264 @State message: string = 'Hello World'; 265 266 build() { 267 RelativeContainer() { 268 Text(this.message) 269 .id('HelloWorld') 270 .fontSize(50) 271 .fontWeight(FontWeight.Bold) 272 .alignRules({ 273 center: { anchor: '__container__', align: VerticalAlign.Center }, 274 middle: { anchor: '__container__', align: HorizontalAlign.Center } 275 }) 276 .onClick(async () => { 277 let context = getContext(this); 278 279 // 数据准备 280 const count = 5 281 let valueBucketArray = collections.Array.create<SharedValuesBucket | undefined>(count, undefined); 282 for (let i = 0; i < count; i++) { 283 let v: IValueBucket = { 284 id: i, 285 name: "zhangsan" + i, 286 age: 20, 287 salary: 5000 + 50 * i 288 }; 289 valueBucketArray[i] = new SharedValuesBucket(v); 290 } 291 await taskpool.execute(create, context) 292 await taskpool.execute(insert, context, valueBucketArray) 293 let index = 0 294 let ret: collections.Array<SharedValuesBucket> = 295 await taskpool.execute(query, context) as collections.Array<SharedValuesBucket> 296 for (let v of ret.values()) { 297 console.info(`Row[${index}].id = ${v.id}`) 298 console.info(`Row[${index}].name = ${v.name}`) 299 console.info(`Row[${index}].age = ${v.age}`) 300 console.info(`Row[${index}].salary = ${v.salary}`) 301 index++ 302 } 303 await taskpool.execute(clear, context) 304 }) 305 } 306 .height('100%') 307 .width('100%') 308 } 309 } 310 ``` 311 312## 复杂类实例对象使用Sendable进行大容量数据库操作 313 314普通类实例对象的属性可持有Sendable类实例对象。<br/> 315对于复杂的普通类实例对象,可以先将相应数据库数据字段封装为Sendable类实例对象,再由普通类实例对象持有,从而降低跨线程开销。 316 3171. 定义数据库中的数据格式,可采用Sendable,减少跨线程耗时。 318 319 ```ts 320 // SharedValuesBucket.ets 321 export interface IValueBucket { 322 id: number; 323 name: string; 324 age: number; 325 salary: number; 326 } 327 328 @Sendable 329 export class SharedValuesBucket implements IValueBucket { 330 id: number = 0; 331 name: string = ""; 332 age: number = 0; 333 salary: number = 0; 334 335 constructor(v: IValueBucket) { 336 this.id = v.id; 337 this.name = v.name; 338 this.age = v.age; 339 this.salary = v.salary; 340 } 341 } 342 ``` 343 3442. 定义普通类实例对象,持有Sendable类实例对象。 345 346 ```ts 347 // Material.ets 348 import { SharedValuesBucket } from './SharedValuesBucket'; 349 import { collections } from '@kit.ArkTS'; 350 351 export class Material { 352 seq: number = 0; 353 materialName: string = ""; 354 // ... 省略其他属性 355 buckets: collections.Array<SharedValuesBucket | undefined>; 356 357 constructor(seq: number, materialName: string, buckets: collections.Array<SharedValuesBucket | undefined>) { 358 this.seq = seq; 359 this.materialName = materialName; 360 this.buckets = buckets; 361 } 362 363 getBuckets() : collections.Array<SharedValuesBucket | undefined>{ 364 return this.buckets; 365 } 366 367 setBuckets(buckets: collections.Array<SharedValuesBucket | undefined>) { 368 this.buckets = buckets; 369 } 370 } 371 ``` 372 3733. UI主线程发起,在子线程进行数据的增删改查等操作。 374 375 ```ts 376 // Index.ets 377 import { relationalStore, ValuesBucket } from '@kit.ArkData'; 378 import { collections, taskpool } from '@kit.ArkTS'; 379 import { IValueBucket, SharedValuesBucket } from './SharedValuesBucket'; 380 import { Material } from './Material'; 381 382 @Concurrent 383 async function create(context: Context) { 384 const CONFIG: relationalStore.StoreConfig = { 385 name: "Store.db", 386 securityLevel: relationalStore.SecurityLevel.S1, 387 }; 388 389 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 390 let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG); 391 console.info(`Create Store.db successfully!`); 392 393 // 创建表 394 const CREATE_TABLE_SQL = "CREATE TABLE IF NOT EXISTS test (" + 395 "id INTEGER PRIMARY KEY AUTOINCREMENT, " + 396 "name TEXT NOT NULL, " + 397 "age INTEGER, " + 398 "salary REAL, " + 399 "blobType BLOB)"; 400 await store.executeSql(CREATE_TABLE_SQL); 401 console.info(`Create table test successfully!`); 402 } 403 404 @Concurrent 405 async function insert(context: Context, valueBucketArray: collections.Array<SharedValuesBucket | undefined>) { 406 const CONFIG: relationalStore.StoreConfig = { 407 name: "Store.db", 408 securityLevel: relationalStore.SecurityLevel.S1, 409 }; 410 411 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 412 let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG); 413 console.info(`Create Store.db successfully!`); 414 415 // 数据插入 416 await store.batchInsert("test", valueBucketArray as Object as Array<ValuesBucket>); 417 } 418 419 @Concurrent 420 async function query(context: Context): Promise<collections.Array<SharedValuesBucket | undefined>> { 421 const CONFIG: relationalStore.StoreConfig = { 422 name: "Store.db", 423 securityLevel: relationalStore.SecurityLevel.S1, 424 }; 425 426 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 427 let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG); 428 console.info(`Create Store.db successfully!`); 429 430 // 获取结果集 431 let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates("test"); 432 let resultSet = await store.query(predicates); // 查询所有数据 433 console.info(`Query data successfully! row count:${resultSet.rowCount}`); 434 let index = 0; 435 let result = collections.Array.create<SharedValuesBucket | undefined>(resultSet.rowCount, undefined) 436 resultSet.goToFirstRow() 437 do { 438 let v: IValueBucket = { 439 id: resultSet.getLong(resultSet.getColumnIndex("id")), 440 name: resultSet.getString(resultSet.getColumnIndex("name")), 441 age: resultSet.getLong(resultSet.getColumnIndex("age")), 442 salary: resultSet.getLong(resultSet.getColumnIndex("salary")) 443 }; 444 result[index++] = new SharedValuesBucket(v) 445 } while (resultSet.goToNextRow()); 446 resultSet.close(); 447 return result 448 } 449 450 @Concurrent 451 async function clear(context: Context) { 452 const CONFIG: relationalStore.StoreConfig = { 453 name: "Store.db", 454 securityLevel: relationalStore.SecurityLevel.S1, 455 }; 456 457 // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name 458 await relationalStore.deleteRdbStore(context, CONFIG); 459 console.info(`Delete Store.db successfully!`); 460 } 461 462 function initMaterial() : Material { 463 // 数据准备 464 const count = 5 465 let valueBucketArray = collections.Array.create<SharedValuesBucket | undefined>(count, undefined); 466 for (let i = 0; i < count; i++) { 467 let v: IValueBucket = { 468 id: i, 469 name: "zhangsan" + i, 470 age: 20, 471 salary: 5000 + 50 * i 472 }; 473 valueBucketArray[i] = new SharedValuesBucket(v); 474 } 475 let material = new Material(1, "test", valueBucketArray); 476 return material; 477 } 478 479 @Entry 480 @Component 481 struct Index { 482 @State message: string = 'Hello World'; 483 484 build() { 485 RelativeContainer() { 486 Text(this.message) 487 .id('HelloWorld') 488 .fontSize(50) 489 .fontWeight(FontWeight.Bold) 490 .alignRules({ 491 center: { anchor: '__container__', align: VerticalAlign.Center }, 492 middle: { anchor: '__container__', align: HorizontalAlign.Center } 493 }) 494 .onClick(async () => { 495 let context = getContext(this); 496 let material = initMaterial(); 497 await taskpool.execute(create, context); 498 await taskpool.execute(insert, context, material.getBuckets()); 499 let index = 0; 500 let ret: collections.Array<SharedValuesBucket> = 501 await taskpool.execute(query, context) as collections.Array<SharedValuesBucket>; 502 material.setBuckets(ret); 503 for (let v of ret.values()) { 504 console.info(`Row[${index}].id = ${v.id}`); 505 console.info(`Row[${index}].name = ${v.name}`); 506 console.info(`Row[${index}].age = ${v.age}`); 507 console.info(`Row[${index}].salary = ${v.salary}`); 508 index++; 509 } 510 await taskpool.execute(clear, context); 511 }) 512 } 513 .height('100%') 514 .width('100%') 515 } 516 } 517 ```