春季启动中的REDIS事务+科特林

发布于 2025-01-22 03:51:20 字数 813 浏览 0 评论 0原文

我试图从Kotlin编写的Spring Boot应用程序中对Redis实例执行交易。我遵循推荐Spring Doc 有关实现这一目标的最佳实践。

但是,我正在为Kotlin实施而苦苦挣扎。具体来说,我不知道如何使用通用方法实现Java通用接口,以使其在Kotlin代码中起作用:

redisTemplate.execute(object : SessionCallback<List<String>> {
  override fun <K : Any?, V : Any?> execute(operations: RedisOperations<K, V>): List<String>? {
    operations.multi()
    operations.opsForValue().set("key", "value")
    return operations.exec()
  }
})

上面的代码抱怨set方法期望参数具有类型kv分别找到字符串

是否有一种优雅的方法如何在Kotlin中嵌入界面实现,而无需使用未经检查的铸造或其他综合方法来制作这项工作?

I am trying to execute a transaction on a Redis instance from within Spring Boot application written in Kotlin. I have followed the recommendation in Spring Doc on the best practice to achieve this.

I am struggling with the Kotlin implementation, however. Specifically, I don't know how to implement the Java generic interface with a generic method to make it work in the Kotlin code:

redisTemplate.execute(object : SessionCallback<List<String>> {
  override fun <K : Any?, V : Any?> execute(operations: RedisOperations<K, V>): List<String>? {
    operations.multi()
    operations.opsForValue().set("key", "value")
    return operations.exec()
  }
})

The code above complains that the set method expects parameters with types K and V respectively but String is found instead.

Is there an elegant way how to inline the interface implementation in Kotlin without having to use unchecked casting or other convoluted approaches to make this work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

听风吹 2025-01-29 03:51:20

我认为,由于sessioncallback的界面定义差,您正在面临此问题,并且框架本身正在自行进行不安全。

您会看到,如果我们查看sessionCallback定义在这里我们可以看到它看起来如下:


public interface SessionCallback<T> {
    @Nullable
    <K,V> T execute(RedisOperations<K,V> operations) throws DataAccessException

}

generics k,v参考键和键的类型REDIS的值不是sessionCallback接口的参数,这就是为什么Kotlin编译器很难推断出这些类型的原因:因为execute函数仅处理一个参数类型sessionCallback&lt; t&gt;,而无需将键和值作为参数的类型传递给该接口。

您最好的效果可能是通过进行一些受控的不安全铸件,使用扩展功能和内联类型在该API周围提供一个漂亮的包装器。

这样的事情可能就足够了:

inline fun <reified K : Any?, reified V: Any?, reified T> RedisTemplate<K, V>.execute(crossinline callback: (RedisOperations<K,V>) -> T?): T?{
   val callback = object : SessionCallback<T> {
        override fun <KK, VV> execute(operations: RedisOperations<KK,VV>) = callback(operations as RedisOperations<K, V>) as T?
   }
   return execute(callback)
}

然后您可以通过执行以下操作:

fun doSomething(redisTemplate: RedisTemplate<String, String>) {
    redisTemplate.execute { operations ->
        operations.multi()
        operations.opsForValue().set("key", "value")
        operations.exec() as List<String>
    }
}

,您需要施放.exec()结果,因为没有人使用gressics烦恼并返回list&lt; object&gt;您在官方文档

I think you're facing this problem due to poor interface definition for SessionCallback and the framework itself is doing unsafe casts themselves.

You see, if we take a look into the SessionCallback definition over here we can see that it looks as follows:


public interface SessionCallback<T> {
    @Nullable
    <K,V> T execute(RedisOperations<K,V> operations) throws DataAccessException

}

The generics K,V referring to the type of keys and values from your Redis are not parameters of the SessionCallback interface and that's why the kotlin compiler is having a hard time inferring the type of these: Because the execute function only takes a parameter of type SessionCallback<T> without passing the types of keys and values as parameters to that interface.

Your best-effort might be to provide a nice wrapper around that API using extension functions and inline generic types by doing some controlled unsafe casts.

Something like this might be enough:

inline fun <reified K : Any?, reified V: Any?, reified T> RedisTemplate<K, V>.execute(crossinline callback: (RedisOperations<K,V>) -> T?): T?{
   val callback = object : SessionCallback<T> {
        override fun <KK, VV> execute(operations: RedisOperations<KK,VV>) = callback(operations as RedisOperations<K, V>) as T?
   }
   return execute(callback)
}

Which then you can consume by doing:

fun doSomething(redisTemplate: RedisTemplate<String, String>) {
    redisTemplate.execute { operations ->
        operations.multi()
        operations.opsForValue().set("key", "value")
        operations.exec() as List<String>
    }
}

And yes, you need to cast the .exec() result because nobody bothered using generics and returns a List<Object> as you can see on the official documentation

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文