You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么Google Apps Script的LockService无法完全阻止双击导致的重复提交?

代码存在的核心问题
  • 锁等待超时时间设置过短,精度不可靠
    waitLock(1)设置的1毫秒超时远远低于Google Apps Script的服务调度最小精度,也无法覆盖网络延迟、实例启动的微小波动,极容易出现两个几乎同时发起的请求都通过了锁等待校验,同时拿到锁执行插入逻辑。建议将超时时间调整到300~1000毫秒,确保并发请求只有第一个能拿到锁。
  • 没有主动释放锁,锁持有逻辑不严谨
    你当前的代码在操作完成后没有调用lock.releaseLock()主动释放锁,虽然脚本执行结束后锁会自动失效,但如果后续还有其他逻辑运行,会导致锁被无意义持有更长时间,反而提升了后续合法请求被误拦截的概率。另外你加的Utilities.sleep(10)完全没有必要,反而会拉长锁的持有时间,加剧并发冲突概率,可以直接删除。
  • 锁的获取时机太晚,缺少幂等校验兜底
    你的data变量明显是在获取锁之前就完成读取赋值的,就算锁挡住了一部分并发,也存在两个请求先读取了相同的数据源、再先后抢到锁的情况,这时两个请求都会执行插入逻辑,自然就会出现重复记录。
    建议在拿到锁之后、执行插入操作前,增加一层幂等校验:比如查询第6行附近的记录,判断是否已经存在和当前待插入数据唯一标识一致的记录,如果存在直接终止执行,不要插入。
  • (可选)锁类型适配问题
    如果这个重复插入只出现在同一用户的双击操作场景,可以将LockService.getScriptLock()换成LockService.getUserLock(),针对单个用户的并发请求做隔离,避免影响不同用户的正常操作。
修正后参考代码
//more code above
// 锁获取逻辑尽量提前,避免提前读取公共可变数据
var lock = LockService.getScriptLock();
try{
  lock.waitLock(500); // 调整超时时间为500毫秒,确保并发请求只有第一个能拿到锁
  // 新增幂等校验,根据你的业务唯一标识调整判断逻辑即可
  var existingAValue = ss.getRange("A6").getValue();
  if(existingAValue === data[0][0]){
    return;
  }
  // 执行插入逻辑
  ss.insertRowBefore(6);
  ss.getRange("A6").setValue(data[0][0]);
  ss.getRange("B6").setValue(formatedString);
  ss.getRange("C6").setValue(data[1][0]);
  ss.getRange("D6").setValue(data[2][0]);
  ss.getRange("E6").setValue(data[3][0]);
  ss.getRange("F6").setValue(data[ref][0]);
  SpreadsheetApp.flush();
}
catch(e){
  return;
} finally {
  // 无论执行成功还是失败,主动释放锁
  if(lock.hasLock()){
    lock.releaseLock();
  }
}
//more code bellow

内容的提问来源于stack exchange,提问作者emolano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 08:54:05