【问题标题】:JDBC on Google Apps Script. Exception: Statement cancelled due to timeout or client requestGoogle Apps 脚本上的 JDBC。例外:由于超时或客户端请求而取消语句
【发布时间】:2020-06-04 11:28:12
【问题描述】:

我正在尝试使用来自 Google Apps 脚本的 JDBC 从 Google Cloud SQL 上的 mySQL 数据库中获取数据。但是,我收到了这个错误:

例外:由于超时或客户端请求而取消语句

我可以成功获取一些其他数据。但是,有些数据我不能。

我在 mySQL 工作台上执行了一个成功的查询和一个不成功的查询。我可以在 mySQL 工作台上毫无问题地执行不成功的查询。

我比较了持续时间。

Duration / Fetch
-------------------------------------------
Successful query:     0.140 sec / 0.016 sec
Unsuccessful query:   0.406 sec / 0.047 sec

不成功的查询似乎需要更长的时间。所以,我设置查询超时:

stmt.setQueryTimeout(0);

打算不设置超时(当值设置为零时,表示执行没有超时限制)。然后,我在 Google Apps Script 上执行了它。

但是,它不起作用并得到相同的错误。你能告诉我一个解决方案吗?

【问题讨论】:

    标签: mysql google-apps-script jdbc mysql-workbench


    【解决方案1】:

    这似乎是一个已知问题。星 ★ 和评论issue 让 Google 开发人员优先考虑该问题。在问题解决之前,您可以switch back to rhino runtime

    【讨论】:

    • 感谢您提供的信息。我盯着这个问题。对于解决方案,我切换回旧版运行时。
    【解决方案2】:

    更新以添加第二次修复

    经过反复试验,我找到了解决此问题的方法——一些查询有效,其他查询返回此错误。

    修复 1 共同点是 V8 引擎/新编辑器已将查询转换为多行格式时出现此问题。

    例如,切换到新的编辑器/V8转换的长文本字符串类似于以下:

    var query = "select Street_Number, street_name, street_suffix, street_dir_prefix, postal_code, city, mls, address, unitnumber " 
      +"as unit, uspsid,latitude,longitude from properties.forsale where status = 'active' and zpid is null and property_type = 'residential'"
    

    此查询导致上述错误。该修复程序将较长的查询更改为连续字符串,如下所示:

    var query = "select Street_Number, street_name, street_suffix, street_dir_prefix, postal_code, city, mls, address, unitnumber as unit, uspsid,latitude,longitude from properties.forsale where status = 'active' and zpid is null and property_type = 'residential'"
    

    修复 2

    这个有点令人沮丧。在与数据库的连接方面,V8 并没有那么宽容。在 V8 之前它会自动关闭任何徘徊的连接,但是,看起来 V8 不喜欢那样。我最初编写脚本是为了共享尽可能少的连接,但我注意到有一些我得到了这个错误,并且它是连接可能被“拆分”的那些。例如:

    var conn = getconnection() //this is a connection function I have written
      var date = date || Utilities.formatDate(new Date(), "America/Chicago", "yyyy-MM-dd");
    
      var keyobj = getkeys(undefined,undefined,conn);
      conn = keyobj.conn;
      var results = sqltojson(query, true, conn);
    

    上面的函数导致了这个错误,我假设这是因为函数返回了 'conn' 变量,但是,我将做出一个疯狂的假设,无论出于何种原因,连接都不能在一次有两个单独的函数,因为它既被返回并继续作为对象“keyobj”中的一个值,也作为“conn”。在定义 conn 变量后立即添加 delete keyobj.conn 就可以了:

    var conn = getconnection() //this is a connection function I have written
      var date = date || Utilities.formatDate(new Date(), "America/Chicago", "yyyy-MM-dd");
    
      var keyobj = getkeys(undefined,undefined,conn);
      conn = keyobj.conn;
      delete keyobj.conn;
      var results = sqltojson(query, true, conn);
    

    同时执行这两个修复程序可以阻止此错误并允许脚本继续运行而不会出现问题。

    【讨论】:

    • 我希望这个 Fix 2 能够工作,但在我的情况下我无法弄清楚。我正在使用单行 SQL 查询,并且正在使用“conn = Jdbc.getCloudSqlConnection(url, info)”...没有分割线,也没有辅助函数,我仍然收到错误“异常:由于超时或客户端请求而取消的语句"
    • @Womprat 我实际上隔离了 JDBC 服务和 V8 的一些其他问题。我实施的一种有助于随机发生此错误的解决方案是在循环中调用您的 .execute() 方法,当它遇到此错误时,它将关闭连接并启动新连接并再次尝试。我将循环设置为尝试 5 次,然后在第 5 次抛出错误。最后,JDBC 服务中似乎存在的问题是它如何解释子查询——根本不喜欢很多嵌套的子查询。
    • @Womprat 我还将再次修改我的答案,因为我已经将函数从传递函数到函数的连接更改为传递从函数创建的语句——V8 似乎这样比通过很多功能发送连接本身要好。
    【解决方案3】:

    问题与上面提到的相同,今天失败了,所以我尝试更改旧版本,它对我有用。仅供参考

    【讨论】:

    • 这对 OP 的回答没有帮助。
    【解决方案4】:

    @TheMaster:尝试与 MySQL 的连接,同样的超时问题,即使我尝试了https://developers.google.com/apps-script/guides/jdbc 的示例> Write 500 rows of data to a table in a single batch.

    更糟糕的是,当我恢复到 rhino 界面时,结果是一样的。这使我的整个开发方法崩溃! :(

    [编辑] FWIW,在我看来,Rhino 和 V8 都不喜欢保持连接(或者它是声明?)打开足够长的时间来完成上述 prepareStatement .

    所以我尝试按照上面链接的示例插入 500 条记录,使用准备好的 SQL 语句,它工作正常:

      var conn = sqlGetConnection();
      var start = new Date();
    
      // conn.setAutoCommit(false);
      // var stmt = conn.prepareStatement('INSERT INTO entries '
      //     + '(guestName, content) values (?, ?)');
      // for (var i = 0; i < 500; i++) {
      //   stmt.setString(1, 'Name ' + i);
      //   stmt.setString(2, 'Hello, world ' + i);
      //   stmt.addBatch();
      // }
      // var batch = stmt.executeBatch();
      // conn.commit();
    
      var sql = 'INSERT INTO ' +
        'entries (guestName, content) ' +
        'values ';
      for (var i = 0; i < 500; i++) {
        var col1 = "'" + 'Name ' + i + "'";           // Note that the strings had to be ecapsulated
        var col2 = "'" + 'Hello, world ' + i + "'";   // in quotes to work with this method
        sql = sql + '(' + col1 + ', ' + col2 + '),';
      }
      sql = sql.substr(0,sql.length-1);
      var stmt = conn.createStatement();
      var response = stmt.executeUpdate(sql);  // executeQuery is only for SELECT statements
    
      conn.close();
    
      var end = new Date();
      Logger.log('Time elapsed: %sms, response: %s rows', end - start, response);
    }
    

    【讨论】:

      【解决方案5】:

      当我为 mysql 表中的相同记录提交更新语句时,我遇到了这个问题。 我在程序中的 update 语句之前设置断点,然后启动 2 进程来运行该程序。所以,第一个进程会正确更新mysql表,第二个进程稍后会得到这个异常。

      您需要在选择语句中添加“for update”。因此,当您更新事务中的记录时,第二个过程将得到零而不是异常。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-02
        • 2012-10-18
        • 1970-01-01
        • 2018-05-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多