我们有一个问题,如果它不存在,我们想懒洋洋地创建一个实体。关于如何做到这一点有一些讨论正在进行,我想澄清有关应用引擎交易的一些事情。我将查询限制为单个实体组事务。
我在我的示例中使用Go,但我希望代码对于非Go程序员来说足够清楚。
我的理解是,只有在事务期间未在外部修改实体组时,单个实体组上的事务才会成功。 '实体组时间戳'指示实体组何时被更改存储在实体组的根实体中。因此,在交易期间,当前的实体组时间戳'如果在交易结束时没有改变,那么交易只能被取消。
key := datastore.NewKey(c, "Counter", "mycounter", 0, nil)
count := new(Counter)
err := datastore.RunInTransaction(c, func(c appengine.Context) error {
err := datastore.Get(c, key, count)
if err != nil && err != datastore.ErrNoSuchEntity {
return err
}
count.Count++
_, err = datastore.Put(c, key, count)
return err
}, nil)
在上面的示例中(取自https://cloud.google.com/appengine/docs/go/datastore/transactions),有两个非错误情况,我可以看到:
ErrNoSuchEntity
,而Put用于首次存储计数器。在第二种情况下,可能正在运行另一个相同的事务。如果两个交易都是'获取返回ErrNoSuchEntity
数据存储区如何确保只有一个put成功?我希望没有"实体组时间戳"在数据存储区中进行测试?
交易是否知道它需要测试计数器是否存在才能使Put和整个交易成功?
在这种情况下,是否有可能两个交易成功,一个Put覆盖另一个?
如果有文档或视频等,围绕控制它的机制,我很乐意阅读它。
答案 0 :(得分:3)
来自documentation on transactions:
在事务内部,强制执行可序列化隔离。
我建议在链接wikipedia page上阅读一下,但简而言之,数据存储区将确保最终结果就像两个事务按顺序运行一样。
让两个交易都写一个新的,归零的计数器不可能的结果。
交易是否知道它需要测试计数器是否存在才能使Put和整个交易成功?
以某种方式是:只有在没有重叠的交易触及相同的密钥时,交易才能在第一次尝试时成功。
在这种情况下,是否有可能两个交易成功,一个Put覆盖另一个?
否,如果两个事务时间帧重叠,那么最后一个提交将失败,最终会重试,然后会看到现有的计数器并递增它。
答案 1 :(得分:2)
要回答您的问题,我们必须深入挖掘开发数据存储区的源代码,幸运的是,对于我们来说,有很好的文档记录,只需看看LiveTxn._GrabSnapshot
:
获取此引用的快照,并在必要时创建它。
如果没有为引用的实体组设置快照,则会拍摄快照并存储以供将来读取(这也会设置读取位置),如果我们不再具有一致的快照,则会引发CONCURRENT_TRANSACTION异常。
因此边缘情况与您推测的情况略有不同:两个事务都会创建一个新的时间戳,然后事情会像往常一样工作。在你提出的情况下,第二个交易将重试,计数器将增加两次。
没有关于交易如何工作的深入文档,至少不是这个深层,但源代码实际上不是 很难读;在这种情况下,您可以跟踪library(mvtnorm)
OP <- function(x) {
n <- nrow(x)
temp <- 0
for(i in 1:n) {
for(j in 1:n) {
temp <- temp + dmvnorm(x[i,] - x[j,])
}
}
return(temp)
}
josilber <- function(x) {
n <- nrow(x)
mat1 <- x[rep(1:n, each=n),]
mat2 <- x[rep(1:n, n),]
sum(dmvnorm(mat1-mat2))
}
# 100 x 10 matrix
set.seed(144)
x <- matrix(rnorm(1000), nrow=100)
all.equal(OP(x), josilber(x))
# [1] TRUE
library(microbenchmark)
microbenchmark(OP(x), josilber(x))
# Unit: milliseconds
# expr min lq mean median uq max neval
# OP(x) 654.553137 696.28275 738.655380 719.058485 760.699813 1194.5594 100
# josilber(x) 2.775881 2.95865 6.789969 4.346013 5.948481 66.0617 100
错误的跟踪。