2

我的问题是如何确保在并发访问时不会丢失任何数据。

我将脚本发布为网络应用程序。我想向 DATA_SHEET 添加新行。处理提交按钮的函数如下所示:

function onButtonSubmit(e) {
  var app = UiApp.getActiveApplication();
  var lock = LockService.getPublicLock();
  while (! lock.tryLock(1000))
    ;
  var ssheet = SpreadsheetApp.openById(SHEET_ID);
  var sheet = ssheet.getSheetByName(DATA_SHEET);
  var lastRow = sheet.getLastRow();
  var lastCol = sheet.getLastColumn();
  var rangeToInsert = sheet.getRange(lastRow+1, 1, 1, lastCol);
  var statText = rangeToInsert.getA1Notation();
  rangeToInsert.setValues(<some data from webapp form>);
  app.getElementById('statusLabel').setText(statText);
  lock.releaseLock();
  return app;
}

但这似乎行不通。当我打开两个表单并在一秒钟内单击提交按钮时,它会在 statsLabel 中显示相同的范围并将数据写入相同的范围。所以我从一种表格中丢失了数据。

这段代码有什么问题?似乎 tryLock() 不会阻止脚本。

还有其他方法可以防止对工作表的并发写访问吗?

4

3 回答 3

5

可能值得一看appendRow(),而不是使用getLastRow()/setValues()等。

允许将行原子附加到电子表格;即使脚本的多个实例同时运行,也可以安全使用。以前,必须调用 getLastRow(),然后写入该行。但如果脚本的两个调用同时运行,它们可能都读取相同的 getLastRow() 值,然后覆盖彼此的值。

于 2012-10-09T22:02:39.717 回答
0

使用带锁的 getLastRow()/setValues() 时必须插入此代码。

SpreadsheetApp.flush();
// before
lock.releaseLock();
于 2014-11-30T22:22:15.900 回答
0
while (! lock.tryLock(1000))
    ;

似乎有点 hinky。试试这个:

  if (lock.tryLock(30000))  {
    // I got the lock!  Wo000t!!!11 Do whatever I was going to do!
  } else {
    // I couldn’t get the lock, now for plan B :(
    GmailApp.sendEmail(“admin@example.com”, “epic fail”,
        “lock acquisition fail!”);
  }

http://googleappsdeveloper.blogspot.com/2011/10/concurrency-and-google-apps-script.html

于 2012-10-09T21:34:32.627 回答