Ionic / Angular并发SQLite连接和写入失败

时间:2016-04-21 15:53:17

标签: angularjs sqlite asynchronous ionic-framework

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

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

<div>
    <canvas width="300"
            height="300"
            id="myCanvas"
            tag-canvas
            canvas-id="tags"
            outline-colour="#ff00ff"
            text-font="Arial"
            text-colour="#ff00ff"
            reverse="true"
            depth="0.8"
            max-speed="0.05"
            weight-mode="both" 
            weight="true"></canvas>
</div>
<div id="tags" style="font-size: 50%;">
    <a ng-repeat="word in wordList" href="{{word.href}}" style="font-size: {{word.fontSize}}">{{word.text}}</a>
</div>

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

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

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

app.js

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

services.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;
        }

我确定我遗漏了有关角度,承诺和sqlite锁定的基本信息。如果有人有建议我真的很感激。

1 个答案:

答案 0 :(得分:0)

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

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

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