sql - Cordova 使用事务将大文件导入数据库

标签 sql typescript cordova ionic-framework transactions

我有一个大约 17 MB 的 txt 文件,我必须解析它,逐行拆分它,然后使用事务将它添加到数据库中。 如果文件太大而我尝试打开它,应用程序将耗尽内存,所以我尝试分段读取它,然后将每一段导入数据库。由于交易,数据库中输入的数据不正确。 有一部分用到的代码:

await file_reader.resolveLocalFilesystemUrl(path + file).then(async (file_entry: any) => {

  await file_entry.file(async (file) => {

    let reader = new FileReader();

     reader.onprogress = async (reader_result: any) => {

       let loaded = _.cloneDeep(reader_result.loaded);
       let total = _.cloneDeep(reader_result.total);
       let is_last_element: boolean = _.cloneDeep(loaded == total);
       let i: number = 0;
       let document_length = this.sync_parser.getReaderLength();
       let event_type: number = this.sync_parser.getEventType();

       content = iconv.encode(reader.result, encoding).toString();

       await this.db.db.transaction(async (database: any) => {
         while (document_length >= i) {
           if (event_type == SyncParserIo.START_TAG) {
             this.table = await this.newHeader(this.sync_parser.getName());
           } else if (event_type == SyncParserIo.END_TAG) {
             // this.file_content = null;
           } else if (event_type == SyncParserIo.ROW) {
             // here I execute basic_update_insert function 
           }
           event_type = this.sync_parser.next(i);
           i++;
         }

       }).then(()=>{
        this.logger.info(this.TAG, "End document from transaction");
       }).catch((e)=>{
        //log
       });

       if (is_last_element) {
        resolve(true);
       }

     };

     await reader.readAsBinaryString(file);
  }); 
}).catch((e) => {
  this.logger.error("FileSystem Error", e.message);
  return reject(e);
});


protected basic_update_insert(table, rows_map, where, where_bindings, database?) {
 let db_query = database != null ? database : this.database;
 let update_query_util: any = DbUtil.update(table, rows_map, where, where_bindings);
 let insert_query_util: any = DbUtil.insert(table, rows_map);

 this.import_result = null;

 db_query.executeSql(update_query_util.query, update_query_util.bindings, (tx, res) => {

   if (res.rowsAffected === 0) {
     tx.executeSql(insert_query_util.query, insert_query_util.bindings, (tx2, insert_result) => {
       if (insert_result.insertId != null) {
         this.import_result = ImporterIo.RESULT_OK;
       }
     }, (e) => {
       this.import_result = ImporterIo.ERROR_INSERT_ROW;
     });

   } else if (res.rowsAffected === 1) {
     this.import_result = ImporterIo.RESULT_OK;
   } else if (res.rowsAffected > 1) {
     this.import_result = ImporterIo.RESULT_OK;
   }

 }, (e) => {
   this.logger.error(this.TAG, `error from ${table} update`, e);
   this.import_result = ImporterIo.ERROR_UPDATE_ROW;
 });
}

最佳答案

您可能会发现 cordova-sqlite-porter有用(有一个 Ionic Native Typescript wrapper )。 它包装了 SQLite DB API,允许您向它传递格式为 SQL 语句或 JSON 的数据转储。

对于如此大量的数据,将数据转换为插件支持的 JSON 结构可能符合您的兴趣,因为它将 JSON 转换为 batched inserts在插件示例项目中,当导入数据的速度提高 100 倍时,这会导致明显的性能改进。

或者,您可能希望手动修改 SQL INSERT 语句以利用 UNION SELECT 优化作为 outlined in this answer .

关于sql - Cordova 使用事务将大文件导入数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53374415/

相关文章:

sql - SQL查询以选择具有其他产品相同成分的产品

Angular 4 http补丁不适用于调用但适用于 postman

angular - Angular 12子组件如何将输入值传递给父组件?

angularjs - 混合应用程序 IFRAME youtube 嵌入不起作用

javascript - 优化 iOS Web App 的音频

mysql - 如何使用 Mysql SUM 和 JOIN

mysql - 此查询中的 SQL 错误

mysql - 有什么方法可以显示 `gunzip < database.sql.gz | mysql ...` 进程的进度吗?

dictionary - TypeScript 中的 C# 字典?

iphone - 相机在手机间隙中无法使用