private def getVersionTime(db: RedisClient, interval: Long)(implicit ec: ExecutionContext): Future[Long] = {
import akka.util.ByteString
import redis.ByteStringFormatter
implicit val byteStringLongFormatter = new ByteStringFormatter[Long] {
def serialize(data: Long): ByteString = ByteString(data.toString.getBytes)
def deserialize(bs: ByteString): Long = bs.utf8String.toLong
}
db.get[Long]("versionTime").map {
case Some(v) => loggerF.info(s"Retrieved version time ${v}")
v
case None => val current = System.currentTimeMillis()
db.setex[Long]("versionTime", (current / 1000) + interval, current)
loggerF.info(s"set version time ${current}")
current
}
it("check with multiple tasks"){
val target = 10
val latch = new java.util.concurrent.CountDownLatch(target)
(1 to target).map{t =>
getVersionTime(prodDb, 10).map{r => print("\n" + r); latch.countDown()}
}
assert(latch.await(10, TimeUnit.SECONDS))
}
14:52:46.692[pool-1-thread-12]信息EndtoEnditTests-设置版本时间1548062566687 14:52:46.693[pool-1-thread-6]信息EndtoEnditTests-设置版本时间1548062566687 14:52:46.693[pool-1-thread-20]信息EndtoEndittest-设置版本时间1548062566687 14:52:46.692[pool-1-thread-2]信息EndtoEndittest-设置版本时间1548062566686 14:52:46.692[pool-1-thread-10]信息EndtoEndittest-设置版本时间1548062566687 14:52:46.693[pool-1-thread-8]信息EndtoEndittest-设置版本时间1548062566687 14:52:46.692[pool-1-thread-4]信息测试-设置版本时间1548062566686 14:52:46.692[pool-1-thread-11]信息EndToEndITTests-设置版本时间1548062566687 14:52:46.692[pool-1-thread-9]信息EndtoEndtoEnditTests-设置版本时间1548062566687 14:52:46.692[pool-1-thread-7]信息EndtoEndtoEnditTests-设置版本时间1548062566687
预期的行为是-设置版本时间应该来一次,对于检索到的其余线程,版本时间应该打印出来。我想我需要在这里使用transaction,以便将get和setex包装在watch和exec中
private def getVersionTimeTrans(db: RedisClient, interval: Long): Long = {
import akka.util.ByteString
import redis.ByteStringFormatter
implicit val byteStringLongFormatter = new ByteStringFormatter[Long] {
def serialize(data: Long): ByteString = ByteString(data.toString.getBytes)
def deserialize(bs: ByteString): Long = bs.utf8String.toLong
}
val redisTransaction = db.transaction()
redisTransaction.watch("versionTime")
val result: Future[Long] = redisTransaction.get[Long]("versionTime").map {
case Some(v) => loggerF.info(s"Retrieved version time ${v}")
v
case None => val current = System.currentTimeMillis()
redisTransaction.setex[Long]("versionTime", (current / 1000) + interval, current)
loggerF.info(s"set version time ${current}")
current
}
redisTransaction.exec()
val r = for {
i <- result
} yield {
i
}
Await.result(r, 10 seconds)
}
测试
it("check with multiple threads "){
val target = 10
val latch = new java.util.concurrent.CountDownLatch(target)
(1 to target).map{t =>
Future(getVersionTimeTrans(prodDb, 10)).map{r => latch.countDown()}
}
assert(latch.await(10, TimeUnit.SECONDS))
}
对于这个测试,输出也是一样的。我不知道如何正确地将它包装在事务中。请帮忙。
研究一下rediscala实现,您似乎不能使用我在原始答案中建议的乐观锁定(见下文),因为在rediscala中,TransactionBuilder
直到exec
命令才会发送watch
命令,这使得它非常无用。GitHub上有一个老的封闭错误,它引用了另一个SO问题,正好是这个场景,答案是
在rediscala中,您不能在事务内部读取,因为您将阻止客户端进行其他请求。我建议您试着看看是否可以在LUA脚本中进行检查。(在lua脚本中转换事务)
几个月后
原始答案
我没有活的Redis来测试它,但查看Redis事务文档,它看起来Redis不支持SQL风格的事务,就像你想象的那样。它支持原子操作,但不能执行“启动事务-获取数据-检查-可能修改-提交”的循环。在exec
命令到达之前,所有“获取数据”命令都将排队。这意味着您不能在同一事务中执行get和set之间的任何检查。
如果您查看该文档的“使用check-and-set的乐观锁定”部分,您可以看到实现行为的正确方法是:
问题内容: 当我的密钥在Redis数据存储区中过期时,我正在尝试使用Redis实施过期密钥通知。redis网站提供了一些有关http://redis.io/topics/notifications的描述,但是我无法找到任何示例,例如使用Jedis的redis java客户端如何做到这一点? 任何可能的带有插图的代码都将非常有用,因为它们是redis的新功能。 问题答案: 您只能使用 pub-sub
当我的密钥在redis数据存储中过期时,我试图用redis实现过期密钥通知。redis网站提供了一些如何http://redis.io/topics/notifications,但我找不到任何像Jedis这样使用redis java客户端的例子? 任何可能的带有插图的代码都会非常有用,因为我是redis的新手。
问题内容: 当我的Redis存储区中的易失性密钥过期时,我想收到通知。redis网站在http://redis.io/topics/notifications中提供了一些有关如何实现此目标的描述,但我想知道是否可以使用python redis api来完成。 设置后:在我的redis.conf文件中 并进行测试: 仅在被调用时被调用,但没有按预期在五秒钟后被调用 问题答案: 惊喜(当密钥的生存时间
当我的redis存储中的易失性密钥过期时,我希望得到通知。redis网站提供了一些关于如何在http://redis.io/topics/notifications中实现这一点的描述,但我想知道是否可以使用python redis api来完成。 设置后: 并将其作为测试运行: 只有在被调用时才被调用,但没有像预期的那样晚五秒钟
问题内容: 我们有以下用例:每当某个密钥过期时,我们都需要根据其值来得到通知并执行某些操作。但是,当redis触发该事件时,当我们稍后尝试访问它时,该密钥已经从数据库中删除了,这当然是可以预期的。 现在,有一种方法可以在过期后再次访问该条目?我猜不会。 第二种选择:有没有一种方法可以让redis在发送这些事件时发布整个值对象而不是仅仅发布键?我想可以通过Lua添加它,但是如果可能的话,我希望有一个
问题内容: 我正在使用Bottle开发应用程序。在我的注册表中,我要通过邮件确认带有唯一密钥的电子邮件。我将此密钥存储在REDIS中,有效期为4天。如果用户未在4天内确认电子邮件,则密钥将过期。为此,我想从数据库(mongoDB)中永久删除用户条目。 当然,我不需要对我的Redis服务器进行连续轮询来检查密钥是否存在。 有什么办法可以从Redis获得回调吗? 或者还有其他有效的方法吗? 问题答案: