• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 : Context = this.getUIContext().getHostContext() as Context;
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 : Context = this.getUIContext().getHostContext() as Context;
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类实例对象。
315
316对于复杂的普通类实例对象,可以先将相应数据库数据字段封装为Sendable类实例对象,再由普通类实例对象持有,从而降低跨线程开销。
317
3181. 定义数据库中的数据格式,可采用Sendable,减少跨线程耗时。
319
320   ```ts
321   // SharedValuesBucket.ets
322   export interface IValueBucket {
323     id: number;
324     name: string;
325     age: number;
326     salary: number;
327   }
328
329   @Sendable
330   export class SharedValuesBucket implements IValueBucket {
331     id: number = 0;
332     name: string = "";
333     age: number = 0;
334     salary: number = 0;
335
336     constructor(v: IValueBucket) {
337       this.id = v.id;
338       this.name = v.name;
339       this.age = v.age;
340       this.salary = v.salary;
341     }
342   }
343   ```
344
3452. 定义普通类实例对象,持有Sendable类实例对象。
346
347   ```ts
348   // Material.ets
349   import { SharedValuesBucket } from './SharedValuesBucket';
350   import { collections } from '@kit.ArkTS';
351
352   export class Material {
353     seq: number = 0;
354     materialName: string = "";
355     // ... 省略其他属性
356     buckets: collections.Array<SharedValuesBucket | undefined>;
357
358     constructor(seq: number, materialName: string, buckets: collections.Array<SharedValuesBucket | undefined>) {
359       this.seq = seq;
360       this.materialName = materialName;
361       this.buckets = buckets;
362     }
363
364     getBuckets() : collections.Array<SharedValuesBucket | undefined>{
365       return this.buckets;
366     }
367
368     setBuckets(buckets: collections.Array<SharedValuesBucket | undefined>) {
369       this.buckets = buckets;
370     }
371   }
372   ```
373
3743. UI主线程发起,在子线程进行数据的增删改查等操作。
375
376   ```ts
377   // Index.ets
378   import { relationalStore, ValuesBucket } from '@kit.ArkData';
379   import { collections, taskpool } from '@kit.ArkTS';
380   import { IValueBucket, SharedValuesBucket } from './SharedValuesBucket';
381   import { Material } from './Material';
382
383   @Concurrent
384   async function create(context: Context) {
385     const CONFIG: relationalStore.StoreConfig = {
386       name: "Store.db",
387       securityLevel: relationalStore.SecurityLevel.S1,
388     };
389
390     // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name
391     let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG);
392     console.info(`Create Store.db successfully!`);
393
394     // 创建表
395     const CREATE_TABLE_SQL = "CREATE TABLE IF NOT EXISTS test (" +
396       "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
397       "name TEXT NOT NULL, " +
398       "age INTEGER, " +
399       "salary REAL, " +
400       "blobType BLOB)";
401     await store.executeSql(CREATE_TABLE_SQL);
402     console.info(`Create table test successfully!`);
403   }
404
405   @Concurrent
406   async function insert(context: Context, valueBucketArray: collections.Array<SharedValuesBucket | undefined>) {
407     const CONFIG: relationalStore.StoreConfig = {
408       name: "Store.db",
409       securityLevel: relationalStore.SecurityLevel.S1,
410     };
411
412     // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name
413     let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG);
414     console.info(`Create Store.db successfully!`);
415
416     // 数据插入
417     await store.batchInsert("test", valueBucketArray as Object as Array<ValuesBucket>);
418   }
419
420   @Concurrent
421   async function query(context: Context): Promise<collections.Array<SharedValuesBucket | undefined>> {
422     const CONFIG: relationalStore.StoreConfig = {
423       name: "Store.db",
424       securityLevel: relationalStore.SecurityLevel.S1,
425     };
426
427     // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name
428     let store: relationalStore.RdbStore = await relationalStore.getRdbStore(context, CONFIG);
429     console.info(`Create Store.db successfully!`);
430
431     // 获取结果集
432     let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates("test");
433     let resultSet = await store.query(predicates); // 查询所有数据
434     console.info(`Query data successfully! row count:${resultSet.rowCount}`);
435     let index = 0;
436     let result = collections.Array.create<SharedValuesBucket | undefined>(resultSet.rowCount, undefined)
437     resultSet.goToFirstRow()
438     do {
439       let v: IValueBucket = {
440         id: resultSet.getLong(resultSet.getColumnIndex("id")),
441         name: resultSet.getString(resultSet.getColumnIndex("name")),
442         age: resultSet.getLong(resultSet.getColumnIndex("age")),
443         salary: resultSet.getLong(resultSet.getColumnIndex("salary"))
444       };
445       result[index++] = new SharedValuesBucket(v)
446     } while (resultSet.goToNextRow());
447     resultSet.close();
448     return result
449   }
450
451   @Concurrent
452   async function clear(context: Context) {
453     const CONFIG: relationalStore.StoreConfig = {
454       name: "Store.db",
455       securityLevel: relationalStore.SecurityLevel.S1,
456     };
457
458     // 默认数据库文件路径为 context.databaseDir + rdb + StoreConfig.name
459     await relationalStore.deleteRdbStore(context, CONFIG);
460     console.info(`Delete Store.db successfully!`);
461   }
462
463   function initMaterial() : Material {
464     // 数据准备
465     const count = 5
466     let valueBucketArray = collections.Array.create<SharedValuesBucket | undefined>(count, undefined);
467     for (let i = 0; i < count; i++) {
468       let v: IValueBucket = {
469         id: i,
470         name: "zhangsan" + i,
471         age: 20,
472         salary: 5000 + 50 * i
473       };
474       valueBucketArray[i] = new SharedValuesBucket(v);
475     }
476     let material = new Material(1, "test", valueBucketArray);
477     return material;
478   }
479
480   @Entry
481   @Component
482   struct Index {
483     @State message: string = 'Hello World';
484
485     build() {
486       RelativeContainer() {
487         Text(this.message)
488           .id('HelloWorld')
489           .fontSize(50)
490           .fontWeight(FontWeight.Bold)
491           .alignRules({
492             center: { anchor: '__container__', align: VerticalAlign.Center },
493             middle: { anchor: '__container__', align: HorizontalAlign.Center }
494           })
495           .onClick(async () => {
496             let context : Context = this.getUIContext().getHostContext() as Context;
497             let material = initMaterial();
498             await taskpool.execute(create, context);
499             await taskpool.execute(insert, context, material.getBuckets());
500             let index = 0;
501             let ret: collections.Array<SharedValuesBucket> =
502               await taskpool.execute(query, context) as collections.Array<SharedValuesBucket>;
503             material.setBuckets(ret);
504             for (let v of ret.values()) {
505               console.info(`Row[${index}].id = ${v.id}`);
506               console.info(`Row[${index}].name = ${v.name}`);
507               console.info(`Row[${index}].age = ${v.age}`);
508               console.info(`Row[${index}].salary = ${v.salary}`);
509               index++;
510             }
511             await taskpool.execute(clear, context);
512           })
513       }
514       .height('100%')
515       .width('100%')
516     }
517   }
518   ```