Redis transaction in Spring Boot + Kotlin



我正在尝试从Kotlin编写的Spring Boot应用程序中执行Redis实例上的事务。我遵循了Spring文档中关于实现此目标的最佳实践的建议。

我正在努力与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,但却找到了String

是否有一种优雅的方法可以在Kotlin中内联接口实现,而不必使用未检查的强制转换或其他复杂的方法来完成这项工作?

我认为你正面临着这个问题,因为SessionCallback的接口定义很差,框架本身也在做不安全的类型转换。

你看,如果我们看一下这里的SessionCallback定义我们可以看到它是这样的:


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

泛型K,V指的是你的Redis的键和值的类型不是SessionCallback接口的参数,这就是为什么kotlin编译器很难推断这些类型:因为execute函数只接受SessionCallback<T>类型的参数,而不将键和值的类型作为参数传递给该接口。

你最大的努力可能是通过一些受控的不安全类型转换,使用扩展函数和内联泛型类型为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()结果,因为没有人费心使用泛型并返回List<Object>,正如您在官方文档

中看到的那样

最新更新