Cordova импортирует большие файлы в базу данных, используя транзакции - PullRequest
0 голосов
/ 19 ноября 2018

У меня есть текстовый файл размером около 17 МБ, который мне нужно проанализировать, разбить его построчно и затем добавить в базу данных с помощью транзакций. Если файл слишком большой и я пытаюсь открыть его, приложению не хватит памяти, поэтому я попытался прочитать его по частям, а затем импортировать каждый фрагмент в базу данных. Из-за транзакций введенные в БД данные неверны. Есть часть используемого кода:

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;
 });
}

1 Ответ

0 голосов
/ 19 ноября 2018

Вам может пригодиться cordova-sqlite-porter (есть оболочка Ionic Native Typescript ). Он оборачивает API-интерфейс БД SQLite, позволяя передавать ему дамп данных, отформатированный как операторы SQL или как JSON.

При таком большом количестве данных в ваших интересах преобразовать данные в структуру JSON, поддерживаемую плагином, поскольку он переводит JSON в пакетные вставки , которые в примере проекта плагина , приводит к заметному улучшению производительности при импорте данных в 100 раз быстрее.

В качестве альтернативы вы можете переделать операторы SQL INSERT вручную, чтобы использовать оптимизацию UNION SELECT, как указано в этом ответе .

...