2012-10-09 61 views
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()不會阻止腳本。

是否有任何其他方式如何防止併發寫入訪問表單?

+0

看來,在Web應用程序鎖是一個[Google Apps腳本問題(http://code.google.com/p/google-apps-script-issues/issues/detail?id=1776) – Chemik

回答

5

這可能是值得考慮看看appendRow(),而不是使用getLastRow()/setValues()

允許排原子追加到電子表格;可以安全地使用 ,即使腳本的多個實例同時在 上運行也是如此。以前,必須調用getLastRow(),然後將 寫入該行。但是,如果腳本的兩次調用同時在 上運行,則它們都可能讀取getLastRow()的相同值,然後 會覆蓋彼此的值。

+0

謝謝,我會嘗試它tomorow。這是比鎖定更好的解決方案。 – Chemik

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(「[email protected]」, 「epic fail」, 
     「lock acquisition fail!」); 
    } 

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

+0

我想等到鎖被另一個實例釋放。 – Chemik

+0

如果它從未發佈會怎麼樣?如果第一個用戶離開他的電腦,該怎麼辦?你的策略應該只在你需要寫作時鎖定,寫作不應該花費那麼長時間,真的。如果您的爭用超過兩個用戶,則需要更好的解決方案,如數據庫。 –

+0

是的一些數據庫是更好的解決方案,但我必須在谷歌電子表格中做到這一點。無論如何,我可以在n次迭代後循環中斷,然後用錯誤信息結束。在嘗試寫入新行時,我僅在提交按鈕處理程序中使用鎖定。 – Chemik

0

當使用帶鎖的getLastRow()/ setValues()時,您必須插入此代碼。

SpreadsheetApp.flush(); 
// before 
lock.releaseLock(); 
相關問題