我的问题是如何确保在并发访问时不会丢失任何数据。
我将脚本发布为web-app。我想在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()不会阻止脚本。
有没有其他方法可以防止对工作表进行并发写访问?
答案 0 :(得分:5)
可能值得一看appendRow()
,而不是使用getLastRow()
/ setValues()
等。
允许将行原子附加到电子表格;可以使用 即使在脚本的多个实例正在运行时也是安全的 同时。以前,必须调用getLastRow(),然后编写 那一排。但是,如果脚本的两个调用正在运行 同时,它们可能都为getLastRow()读取相同的值,并且 然后覆盖彼此的价值。
答案 1 :(得分:0)
while (! lock.tryLock(1000))
;
似乎有点狡猾。试试这个:
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
答案 2 :(得分:0)
使用带锁定的getLastRow()/ setValues()时必须插入此代码。
SpreadsheetApp.flush();
// before
lock.releaseLock();