【问题标题】:Ionic/Angular concurrent SQLite connections and writes failingIonic/Angular 并发 SQLite 连接和写入失败
【发布时间】:2016-04-22 03:28:20
【问题描述】:

我对 Ionic 和 Angular 都很陌生。我正在尝试写入 SQLite 数据库并且它间歇性地成功。当我执行 for 循环并快速插入记录时,有些成功,有些失败(没有明显错误)。查询执行使用 Promise,因此多个查询可能会尝试同时执行。似乎这会导致 SQLite 或 SQLite 插件中的同步问题。我尝试使用每个 execute() 打开一个新的数据库连接,在每个 execute() 上重新打开现有连接,并且我还尝试过在 app.js 中打开一个全局连接并重用该连接。它们的行为似乎都一样。

自定义的“dbQuery”函数用于构建查询并且是可链接的。这个想法是我的应用程序中可以访问数据库服务的任何地方都可以执行查询并期望结果流入“输出”变量,例如:

var my_query_results = [];
DB.begin().select("*","table1").execute(my_query_results).then(function() {
   console.log("Query complete");
});

这很有效,但问题来自于写入:

var records = [
    {id:1, name:"Bob"},
    {id:2, name:"John"},
    {id:3, name:"Jim"},
];
for (var i = 0; i < records.length; i++) {
   var obj = records[i];
   var result = [];
   DB.begin().debug(true).insert("table1", "(id,name)", "("+obj.id+","+ obj.name+")").execute(result).then(function () {
       console.log("Inserted record", JSON.stringify(obj));
    });
}

有时它会在没有任何记录或明显错误的情况下失败,有时它会成功。如果我随着时间的推移缓慢执行插入,它似乎可以正常工作。

app.js

var db;

angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])

  .run(function ($ionicPlatform, $cordovaSQLite, appConfig, $q) {
    $ionicPlatform.ready(function () {
      db = $cordovaSQLite.openDB({
        name: appConfig.sqlite_db,
        location: appConfig.sqlite_db_location
      });

      dbQuery = function () {
        this.bDebug = false;
        this.query = "";
        this.result = [];
        this.params = [];
        this.debug = function (value) {
          this.bDebug = (value === true ? true : false);
          return this;
        };
        this.rawQuery = function (query) {
           this.query = query;
           return this;
        };
        this.insert = function (table, fields, values) {
          this.query = "INSERT INTO '" + table + "' (" + fields + ") VALUES (" + values + ")";
          return this;
        };
        this.select = function (fields, table) {
          this.query = "SELECT " + fields + " FROM " + table;
          return this;
        };
        this.delete = function (query) {
          this.query = "DELETE FROM " + query;
          return this;
        };
        this.where = function (column, expression, value) {
          expression = expression || "=";
          this.query += " WHERE `" + column + "` " + expression + " ? ";
          this.params[this.params.length] = value;
          return this;
        };
        this.and = function (column, expression, value) {
          expression = expression || "=";
          this.query += " AND '" + column + "' " + expression + " ? ";
          this.params[this.params.length] = value;
          return this;
        };
        this.execute = function (out_var) {
          var self = this;
          this.result = out_var;

          if (this.bDebug) {
            console.log("Compiled query is", this.query);
          }

          var deferred = $q.defer();

          db.open(function () {
            console.log("Opened");
          }, function () {
            console.log("Failed");
          });

          //actually execute the query
          $cordovaSQLite.execute(db, this.query, this.params).then(
            function (res) {
              for (var i = 0; i < res.rows.length; i++) {
                self.result.push(res.rows.item(i));
                console.log("Added row to set", JSON.stringify(res.rows.item(i)));
              }
              if (res.rows.length == 0 && self.bDebug === true) {
                console.log("No results found ");
              }
              deferred.resolve();
            }, function (err) {
              console.error(JSON.stringify(err), this.query);
              deferred.reject();
            });
          return deferred.promise;
        }

services.js

  .factory('DB', function ($ionicPlatform) {
    return {
      begin: function () {
        return new dbQuery();
      }
    }
  })

.factory('DbBootstrap', function ($cordovaSQLite, appConfig, $q, $state, DB) {
    return {
      wipe: function () {
        DB.begin().rawQuery("DELETE FROM table1").execute().then(function () {
          console.log("Purged records");
        });
      },
      init: function () {
        var result = []; //out variable
        DB.begin().rawQuery("CREATE TABLE IF NOT EXISTS table1 (id integer primary key, name text)").execute(result).then(function () {
          console.log("Schema create returned", JSON.stringify(result));
        });

       var records = [
          {
            id: 1, name:'Jim'
            ...
          },
          {
            id: 2, name:'Bob'
            ...
          },
          {
            id: 3, name:'John'
           ...
          }

        ];
        for (var i = 0; i < records.length; i++) {
          var obj = records[i];
          var result = [];
          DB.begin().debug(true).insert("table1", "(id,name)", "(obj.id, obj.name).execute(result).then(function () {
            console.log("Inserted record", JSON.stringify(obj));
          });
        }

    }
})

我确定我错过了有关 Angular、Promise 和 sqlite 锁定的基本知识。如果有人有建议,我将不胜感激。

【问题讨论】:

    标签: angularjs sqlite asynchronous ionic-framework


    【解决方案1】:

    我按照这里的优秀建议解决了这个问题 - Angular/Ionic and async SQLite - ensuring data factory initialised before return

    关键问题是我需要将所有数据库操作包装在 Promise 中,并将它们用于有序的初始化和回调。

        .factory('DB', function ($q, $cordovaSQLite, appConfig) {
        //private variables
        var db_;
    
        // private methods - all return promises
        var openDB_ = function (dbName, location) {
          var q = $q.defer();
          try {
            db_ = $cordovaSQLite.openDB({
              name: dbName,
              location: location
            });
            q.resolve(db_);
          } catch (e) {
            q.reject("Exception thrown while opening DB " + JSON.stringify(e));
          }
    
          return q.promise;
        };
    
        var performQuery_ = function (query, params, out) {
          var q = $q.defer();
          params = params || [];
          out = out || [];
    
          //open the DB
          openDB_(appConfig.sqlite_db, appConfig.sqlite_db_location)
            .then(function (db) {
              //then execute the query
              $cordovaSQLite.execute(db, query, params).then(function (res) {
                //then add the records to the out param
                console.log("Query executed", JSON.stringify(query));
                for (var i = 0; i < res.rows.length; i++) {
                  out.push(res.rows.item(i));
                  console.log("Added row to set", JSON.stringify(res.rows.item(i)));
                }
                if (res.rows.length == 0 && self.bDebug === true) {
                  console.log("No results found ");
                }
              }, function (err) {
                console.log("Query failed", JSON.stringify(query));
                q.reject();
              });
              db_.open(function () {
                q.resolve("DB Opened")
              }, function () {
                q.reject("Failed to open DB");
              });
            }, function (err) {
              console.log(JSON.stringify(err), this.query);
              q.reject(err);
            });
          return q.promise;
        };
    
        // public methods
        var execute = function (query, params, out) {
          var q = $q.defer();
          performQuery_(query, params, out).then(function () {
            q.resolve([query, params]);
          }, function (err) {
            q.reject([query, params, err]);
          });
          return q.promise;
        };
    
        return {
          execute: execute
        };
      })
    

    【讨论】:

      猜你喜欢
      • 2019-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-28
      • 1970-01-01
      • 1970-01-01
      • 2014-03-22
      • 2011-08-13
      相关资源
      最近更新 更多