我有一个带有 Redis 缓存的 kotlin spring 数据应用程序。我想清理 Redis 数据库并使用
redisConnectionFactory.connection.serverCommands().flushAll()
命令。当我单独运行单元测试时,一切正常,没有任何问题。但是,当我尝试运行应用程序中的所有测试(大约有 200 个)甚至来自任何类的测试时,在通过 8 个测试后,所有内容都冻结在命令上 redisConnectionFactory.connection.serverCommands().flushAll()
(我添加了用于调试的日志,我明白了这一点从中)。等待是没有用的,我必须停止测试。不依赖测试;这可以通过不同的测试为不同的班级重现。
也许有人遇到过这种情况,至少可以给我一个提示吗?或者如果有人可以给我建议如何以不同的方式解决我清除缓存的问题,我也会非常感激。
@SpringBootTest
@ExtendWith(SpringExtension::class)
@Import(TestChannelBinderConfiguration::class)
@ContextConfiguration(initializers = [RedisInitializer::class])
@RecordApplicationEvents
abstract class AbstractIntegrationTest {
@Autowired
protected lateinit var redisConnectionFactory: RedisConnectionFactory
@AfterEach
fun clean() {
redisConnectionFactory.connection.serverCommands().flushAll()
}
}
Redis初始化器:
class RedisInitializer : ApplicationContextInitializer<ConfigurableApplicationContext> {
override fun initialize(context: ConfigurableApplicationContext) {
TestPropertyValues.of(
"spring.redis.host=" + REDIS_CONTAINER.host,
"spring.redis.port=" + REDIS_CONTAINER.getMappedPort(REDIS_PORT)
).applyTo(context.environment)
}
companion object {
private const val REDIS_PORT = 6379
private val IMAGE_NAME = DockerImageName.parse("redis:6.2-alpine")
var REDIS_CONTAINER: GenericContainer<*> = GenericContainer<Nothing>(IMAGE_NAME)
.withExposedPorts(REDIS_PORT)
init {
REDIS_CONTAINER.start()
}
}
}
Redis配置:
@Configuration
@EnableCaching
class RedisConfig(
val redisProperties: RedisProperties
) {
@Bean
fun redisTemplate(connectionFactory: RedisConnectionFactory): RedisTemplate<String, Any> =
RedisTemplate<String, Any>().apply {
setConnectionFactory(connectionFactory)
setDefaultSerializer(StringRedisSerializer())
setValueSerializer(redisSerializer())
}
@Bean
fun redisSerializer(): RedisSerializer<Any> {
val objectMapper = ObjectMapper().apply {
setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
}
return Jackson2JsonRedisSerializer(Any::class.java)
.apply {
setObjectMapper(objectMapper)
}
}
@Bean
fun jedisConnectionFactory(): RedisConnectionFactory {
val jedisConnectionFactory = if (redisProperties.sentinel != null) {
JedisConnectionFactory(getSentinelConfiguration())
} else {
JedisConnectionFactory(getStandaloneConfiguration())
}
jedisConnectionFactory.afterPropertiesSet()
return jedisConnectionFactory
}
private fun getSentinelConfiguration(): RedisSentinelConfiguration {
val sentinelConfiguration = RedisSentinelConfiguration()
sentinelConfiguration.setMaster(redisProperties.sentinel.master)
sentinelConfiguration.password = RedisPassword.of(redisProperties.password)
sentinelConfiguration.sentinelPassword = RedisPassword.of(redisProperties.sentinel.password)
sentinelConfiguration.setSentinels(
redisProperties.sentinel.nodes.stream().map { node: String ->
val nodeConf = node.split(":").toTypedArray()
RedisNode(nodeConf[0], nodeConf[1].toInt())
}.collect(Collectors.toList())
)
return sentinelConfiguration
}
/**
* Standalone is used only in integration tests
* when raising the application context and connecting
* to the Redis docker image from the test container.
*/
private fun getStandaloneConfiguration(): RedisStandaloneConfiguration {
val configuration = RedisStandaloneConfiguration()
configuration.hostName = redisProperties.host
configuration.port = redisProperties.port
configuration.password = RedisPassword.of(redisProperties.password)
return configuration
}
}
我用
RedisConnectionFactory
替换了 RedisTemplate
,它对我有帮助:
@SpringBootTest
@ExtendWith(SpringExtension::class)
@Import(TestChannelBinderConfiguration::class)
@ContextConfiguration(initializers = [RedisInitializer::class])
@RecordApplicationEvents
abstract class AbstractIntegrationTest {
@Autowired
protected lateinit var redisTemplate: RedisTemplate<String, Any>
@AfterEach
fun clean() {
redisTemplate.execute { connection: RedisConnection ->
connection.serverCommands().flushDb()
null
}
}
}
此命令
redisConnectionFactory.connection.serverCommands().flushAll()
应该耗尽连接池。这就是为什么你只成功运行了 8 次(显然池配置最多有 8 个连接)
怎么样:
try(var connection = redisConnectionFactory.getConnection()) {
connection.serverCommands().flushDb()
}
它保证连接将被释放。