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