WebSQL事务不会在JS回调函数中运行

我正在使用PhoneGap和jQuery Mobile。 我试图从远程位置获取一些JSON数据,然后用它填充本地WebSQL数据库。 这是我的JSfunction:

function getLocations() { var tx = window.openDatabase('csdistroloc', '1.0', 'Distro DB', 1000000); tx.transaction(function(tx) { tx.executeSql('DROP TABLE IF EXISTS locations'); //this line works! tx.executeSql('CREATE TABLE IF NOT EXISTS locations (id, name, address, postalcode, phone, category)'); //this line works! $.ajax({ url: "http://mydomain.com/api.php", dataType: 'json', data: { action: "getlocations" }, success: function(data) { tx.executeSql("INSERT INTO locations (id, name, address, postalcode, phone, category) VALUES (2,'cheese','232','seven',5,6)"); //this line produces an error }}); }, dberror, dbsuccess); } 

运行上面的函数会在上面提到的行上给出错误“INVALID_STATE_ERR:DOM Exception 11”。 当我实际尝试使用返回的JSON数据插入数据时,它也会做同样的事情。 我也尝试了$ .getJSON技术,结果完全相同。

任何意见,将不胜感激!

我首先建议不要命名数据库’tx’,而是命名数据库或数据库。 这可能是一个变量命名问题,因为函数参数和数据库变量都被称为“tx”

编辑:我有同样的问题,并通过在回调内进行查询来解决它自己的事务。 像这样:

 success: function(data) { tx.transaction(function(transaction){ transaction.executeSql("INSERT INTO locations (id, name, address, postalcode, phone, category) VALUES (2,'cheese','232','seven',5,6)"); //now more DOM exception! } }} 

我认为问题是在回调被触发时外部事务已经完成,因为webSQL的事务不是同步的。

虽然接受的答案是正确的,但我想扩展它,因为我遇到了同样的问题,答案并没有说明为什么它不能像OP那样有效。

在Web SQL中创建事务时,只有在事务中排队的任何语句时 ,事务处理才会保持活动状态。 一旦事务中的语句管道干涸,引擎就会关闭(提交)事务。 这个想法是当function(tx) { ... }回调运行时,

  1. 它执行所需的所有语句。 executeSql是异步的,因此即使语句尚未执行,它也会立即返回。
  2. 它将控制权返回给Web SQL引擎。

此时,引擎注意到有一些语句排队并在关闭事务之前将它们运行完成。 在你的情况下,会发生什么:

  1. 您调用executeSql两次以排队两个语句。
  2. 你通过ajax请求一些东西。
  3. 你回来了

引擎运行它排队的两个语句。 ajax请求也是异步运行的,但它必须访问网络,因为它可能还没有完成。 此时,语句队列为空,Web SQL引擎决定是时候提交并关闭事务了! 它无法知道将来会有另一个声明! 当ajax调用返回并且它尝试执行INSERT INTO locations ,为时已晚,事务已经关闭。

接受的答案建议的解决方案有效:不要在ajax回调中使用相同的事务,而是创建一个新事务。 不幸的是,它有使用2个事务而不是1的预期陷阱:操作不再是primefaces的。 这可能对您的申请很重要,也可能不重要。

如果交易的primefaces性对您很重要,那么您只有2个资源:

  • 在ajax回调中的一个事务中执行所有操作(所有3个语句)。

    这是我的建议。 我认为在创建表之前等待ajax请求完成后很可能与您的应用程序要求兼容。

  • 按照此处的说明同步执行ajax请求。

    我不推荐。 JavaScript中的异步编程是一件好事。

顺便说一句,我在Promises的上下文中遇到了问题,代码看起来像这样:

 // XXX don't do this, it doesn't work! db.transaction(function(tx) { new Promise(function(resolve, reject) { tx.executeSql( "SELECT some stuff FROM table ....", [], function(tx, result) { // extract the data that are needed for // the next step var answer = result.rows.item( .... ).some_column; resolve(answer); } ) }).then(function(answer) { tx.executeSql( "UPDATE something else", // The answer from the previous query is a parameter to this one [ ... , answer, .... ] ) }); }); 

问题是,使用promises,链接的.then()子句不会在原始promise的解析后立即运行。 它只排队等待以后执行,就像ajax请求一样。 唯一的区别是,与慢速ajax请求不同, .then()子句几乎立即运行。 但“差不多”还不够好:它可能会或者可能不会很快运行,以便在事务关闭之前将下一个SQL语句放入队列中; 因此,代码可能会或可能不会产生取决于定时和/或浏览器实现的无效状态错误。

太糟糕了: Promise在SQL事务中使用会很有用。 上面的伪示例可以很容易地在没有promises的情况下重写,但是一些用例可以极大地利用许多.then()的链以及Promise.all这样的东西来确保整个SQL语句集合在任何订单,但在其他声明之前完成。

我们确实有办法锁定事务,同时执行任何AJAX或其他异步操作。 基本上在调用AJAX之前,你需要启动一个虚拟db操作,并且在该操作成功时检查AJAX是否完成,并再次调用相同的虚拟操作,直到你的AJAX完成。 当AJAX完成后,您现在可以重用事务对象执行下一组executeSQL。 这篇文章在这篇文章中有详细解释。 (我希望有人也不会删除这个答案,就像之前有人在类似的问题上所做的那样)

试试这种方法