当前位置: 首页 > 知识库问答 >
问题:

redis通过事务获取和设置密钥过期

施琦
2023-03-14
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))
}

对于这个测试,输出也是一样的。我不知道如何正确地将它包装在事务中。请帮忙。

共有1个答案

公良琛
2023-03-14

研究一下rediscala实现,您似乎不能使用我在原始答案中建议的乐观锁定(见下文),因为在rediscala中,TransactionBuilder直到exec命令才会发送watch命令,这使得它非常无用。GitHub上有一个老的封闭错误,它引用了另一个SO问题,正好是这个场景,答案是

在rediscala中,您不能在事务内部读取,因为您将阻止客户端进行其他请求。我建议您试着看看是否可以在LUA脚本中进行检查。(在lua脚本中转换事务)

几个月后

原始答案

我没有活的Redis来测试它,但查看Redis事务文档,它看起来Redis不支持SQL风格的事务,就像你想象的那样。它支持原子操作,但不能执行“启动事务-获取数据-检查-可能修改-提交”的循环。在exec命令到达之前,所有“获取数据”命令都将排队。这意味着您不能在同一事务中执行get和set之间的任何检查。

如果您查看该文档的“使用check-and-set的乐观锁定”部分,您可以看到实现行为的正确方法是:

    null
 类似资料:
  • 问题内容: 当我的密钥在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获得回调吗? 或者还有其他有效的方法吗? 问题答案: