我想使用 Groovy 闭包来处理来自 SQL 表的数据。对于每个新行,计算将取决于先前计算的内容。但是,新行可能会在应用程序的进一步运行中变得可用,所以我希望能够重新加载闭包,并使用它在应用程序的上一次运行中最后一次执行闭包时的中间状态进行初始化。
例如,一个打算计算 3 行移动平均值的闭包可以这样实现:
def prev2Val = null
def prevVal = null
def prevId = null
Closure c = { row ->
println([ prev2Val, prevVal, prevId])
def latestVal = row['val']
if (prev2Val != null) {
def movMean = (prev2Val + prevVal + latestVal) / 3
sql.execute("INSERT INTO output(id, val) VALUES (?, ?)", [prevId, movMean])
}
sql.execute("UPDATE test_data SET processed=TRUE WHERE id=?", [row['id']])
prev2Val = prevVal
prevVal = latestVal
prevId = row['id']
}
test_data
有 3 列:(id
自动递增的主键)value
和processed
. 根据前两个值计算移动平均值并将其插入到output
表中,与id
前一行的值相对。已处理的行用 标记processed=TRUE
。
如果所有数据从一开始就可用,则可以这样调用:
sql.eachRow("SELECT id, val FROM test_data WHERE processed=FALSE ORDER BY id", c)
当应用程序运行后新行可用时,问题就出现了。这可以通过每次处理一小批来模拟(例如LIMIT 5
在前面的语句中使用)。
我希望能够在执行结束时转储闭包的完整状态eachRow
(例如,将中间数据保存在数据库中的某个位置)并在我重新运行整个应用程序时再次重新初始化它(通过加载那些来自数据库的中间变量)。
在这个特定示例中,我可以通过存储和的值来手动执行此操作prev2Val
,但我正在寻找一个通用解决方案,其中不需要确切知道使用了哪些变量。prevVal
prevId
也许类似于c.getState()
which 会返回[ prev2Val: 1, prevVal: 2, prevId: 6]
(例如),以及[ prev2Val: 1, prevVal: 2, prevId: 6]
下次执行应用程序时我可以在哪里使用 c.setState() (如果存储了一个状态)。
我还需要sql
从列表中排除。看来这可以使用c.@sql=null
.
我意识到这在一般情况下不太可能起作用,但我正在寻找适合大多数情况的足够通用的东西。如本 Groovy 问题中所述,我已尝试dehydrate
序列化和关闭,但我不确定如何在单个操作中保存和存储所有字段。rehydrate
@
这可能吗?假设闭包使用的变量列表不一定事先知道,是否有更好的方法来记住执行之间的状态?