将谷歌工作表数据导入MySQL表并尝试解决360秒执行限制的编码。我正在使用批处理执行,甚至这无助于导入包含更大数据的工作表。谷歌应用程序脚本中是否有一种方法可以在350秒或者以先到者为准的记录数量中脱离,并让下一次执行从中断处开始捡起它。
var address = 'database_IP_address';
var rootPwd = 'root_password';
var user = 'user_name';
var userPwd = 'user_password';
var db = 'database_name';
var root = 'root';
var instanceUrl = 'jdbc:mysql://' + address;
var dbUrl = instanceUrl + '/' + db;
function googleSheetsToMySQL() {
var RecId;
var Code;
var ProductDescription;
var Price;
var dbconnection = Jdbc.getConnection(dbUrl, root, rootPwd);
var statement = dbconnection.createStatement();
var googlesheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('product');
var data = googlesheet.getDataRange().getValues();
dbconnection.setAutoCommit(false)
for (var i = 1; i < data.length; i++) {
RecId = data[i][0];
Code = data[i][1];
ProductDescription = data[i][2];
Price = data[i][3];
var sql = "{call [dbo].[sp_googlesheetstotable](?,?,?,?)}";
statement = dbconnection.prepareCall(sql);
statement.setString(1, RecId);
statement.setString(2, Code);
statement.setString(3, ProductDescription);
statement.setString(4, Price);
statement.addBatch()
statement.executeBatch()
}
dbconnection.commit()
答案 0 :(得分:1)
在这种情况下我做的是创建一个空表,允许我存储数据库的起始ID,然后我在脚本上设置一个触发器,每10分钟运行一次。为此,只需单击GAS编辑器中播放按钮左侧的小时钟图标即可。
让我们举个例子说我有一个包含1000条记录的数据库,每次触发器运行脚本时我想要提升100条记录。我要创建一张表 - 让我们说&#34; Sheet1&#34; - 最初将0
放在单元格A1中。
在GAS中,我每次运行脚本时都会获得A1的值:
var ss = SpreadsheetApp.openById("XXXXX");
var sheet = ss.getSheetByName("Sheet1");
var a1 = sheet.getRange("A1").getValue();
var a1 = parseInt(a1);
var last_row = a1+100;
然后您的SQL语句应该类似于以下查询:
"SELECT * FROM `table` WHERE `id` >= '"+a1+"' AND `id` < '"+last_row+"'"
查询完成并将结果输出到电子表格后,您就可以A1
更新last_row
:
sheet.getRange("A1").setValue(last_row);
当脚本再次运行时(通过触发器),它将采用新值100
,添加100
(使其成为200
),查询表格以获得更大的结果大于或等于100且小于200,并相应地显示它们。
答案 1 :(得分:1)
是的,只要问题是由循环过程引起的,这很容易实现。如果没有循环则有点棘手,如果是单个操作则不可能。幸运的是,你们似乎是第一种。
本质上我们首先需要知道脚本何时开始,所以我们做了
var startTime = new Date();
获得开始时间。接下来我们需要检查每次迭代后的时间,所以在for
循环内部,我们会添加(我个人首先声明变量而不是var,但这只是我的风格偏好)
var execTime = new Date();
execTime = execTime - startTime
告诉我们脚本执行了多长时间。如果你想获得花哨,你可以检查你的循环平均需要多长时间并检查是否有足够的时间,但通常只是给它一些时间来执行截止就足够了。然后你需要做一些事情。首先,您希望使用
存储您拥有的数据PropertiesService.getScriptProperties().setProperty(key, value)
其中key
是属性的名称,value
是您要存储的对象。如果它是一个数组,请确保使用JSON
对其进行字符串化。您还需要创建一个触发器,以便从您离开的位置开始。详细了解here。你当然可以先创建一个触发器,然后存储属性,没有问题。
以下是在我的脚本中执行此段的函数的示例:
function autoTrigger(passProperties, sysKeys) {
var sysProperties = new systemProperties();
if (typeof sysKeys === 'undefined' || sysKeys === null) {
sysKeys = new systemKeys();
}
var triggerID = ScriptApp.newTrigger('stateRebuild')
.timeBased()
.after(60000)
.create()
.getUniqueId();
Logger.log('~~~ RESTART TRIGGER CREATED ~~~');
//-------------------------------------------------------------------------------------------------
// In order to properly retrieve the time later, it is stored in milliseconds
passProperties.timeframe.start = passProperties.timeframe.start.getTime();
passProperties.timeframe.end = passProperties.timeframe.end.getTime();
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
// Properties are stored in User Properties using JSON
PropertiesService.getUserProperties()
.setProperty(sysKeys.startup.rebuildCache, JSON.stringify(passProperties));
//-------------------------------------------------------------------------------------------------
Logger.log('~~~ CURRENT PROPERTIES STORED ~~~');
return triggerID;
}
现在你必须停止你的脚本。您可以使用throw
执行此操作。我是这样做的:
if (typeof execProperties.nextPageId !== 'undefined' && execProperties.nextPageId) {
if (isTimeUp(startTime, Math.max(averageExec, execTime)) === true) {
autoTrigger(execProperties);
throw new Error('Script reseting');
}
}
我留下1分钟以防万一。
function isTimeUp(start, need) {
var cutoff = 500000 // in miliseconds (5 minutes)
var now = new Date();
return cutoff - (now.getTime() - start.getTime()) < need;
}
请注意,在我的情况下,脚本不会调用相同的函数,因为有不同的启动过程。您需要做的是调整脚本以获取存储在属性中的值。您可以进一步阅读属性here。因此,如果您的脚本可以找到属性,那么您想要做的是删除触发器,检索变量并清除所有这些属性,然后一直跳到循环。这可以通过几个if
语句轻松完成。
希望这有帮助。