我使用连接池创建连接工厂的配置。我有一个连接池。大多数代码都是从Spring RedisAutoConfiguration
中复制的,我已经因特殊原因而禁用了它。
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class JedisConfiguration implements RedisConfiguration {
@Bean
@Scope("prototype")
@Override
public RedisConnectionFactory connectionFactory(RedisProperties redisProperties) {
return createFactory(redisProperties);
}
private static JedisConnectionFactory applyProperties(RedisProperties properties, JedisConnectionFactory factory) {
factory.setHostName(properties.getHost());
factory.setPort(properties.getPort());
factory.setDatabase(properties.getDatabase());
return factory;
}
private static JedisPoolConfig jedisPoolConfig(RedisProperties properties) {
return Optional.ofNullable(properties.getPool())
.map(props -> {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(props.getMaxActive());
config.setMaxIdle(props.getMaxIdle());
config.setMinIdle(props.getMinIdle());
config.setMaxWaitMillis(props.getMaxWait());
return config;
})
.orElseGet(JedisPoolConfig::new);
}
public static JedisConnectionFactory createFactory(RedisProperties properties) {
return applyProperties(properties, new JedisConnectionFactory(jedisPoolConfig(properties)));
}
}
我有字符串键"A"
,"B"
,"C"
映射到带有字符串哈希键的哈希映射,以及从类A
序列化的哈希值json,{{1}分别和B
。
那是C
- > "A"
- > A::toString
和json(A)
以及B
相同。
C
我有测试证明1有效,但我对此有点怀疑但我的问题是最后两个。在调试之后,我观察到在任一操作之后连接都没有返回到池,因此当池耗尽时池被阻塞。
尝试返回但未在连接上调用,因为下面的两个分支失败。取自@Component
public final class UseCase implements InitializingBean {
private static final String A_KEY = "A";
private static final String B_KEY = "B";
private static final String C_KEY = "C";
private final RedisConnectionFactory factory;
private final ObjectMapper objectMapper;
private HashOperations<String, String, A> aMap;
private HashOperations<String, String, B> bMap;
private HashOperations<String, String, C> cMap;
private RedisTemplate<String, ?> template;
private UseCase(RedisConnectionFactory factory, ObjectMapper objectMapper) {
this.factory = factory;
this.objectMapper = objectMapper;
}
private <T> RedisTemplate<String, ?> hashMap(Class<T> vClass) {
RedisTemplate<String, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(stringSerializer());
redisTemplate.setHashKeySerializer(stringSerializer());
redisTemplate.setHashValueSerializer(jacksonSerializer(vClass));
return configure(redisTemplate);
}
private <K, V> RedisTemplate<K, V> configure(RedisTemplate<K, V> redisTemplate) {
redisTemplate.setConnectionFactory(factory);
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
private <T> RedisSerializer<T> jacksonSerializer(Class<T> clazz) {
Jackson2JsonRedisSerializer<T> serializer = new Jackson2JsonRedisSerializer<>(clazz);
serializer.setObjectMapper(objectMapper);
return serializer;
}
private RedisSerializer<String> stringSerializer() {
return new StringRedisSerializer();
}
@Override
public void afterPropertiesSet() throws Exception {
template = hashMap(String.class);
aMap = hashMap(A.class).opsForHash();
bMap = hashMap(B.class).opsForHash();
cMap = hashMap(C.class).opsForHash();
}
void put(A a, B b, C c) {
template.multi();
aMap.put(A_KEY, a.toString(), a);
bMap.put(B_KEY, b.toString(), b);
cMap.put(C_KEY, c.toString(), c);
template.exec();
}
A getA(String aKey) {
return aMap.get(A_KEY, aKey);
}
}
RedisConnectionUtils
答案 0 :(得分:3)
我认为问题在于,调用exec()
并不会告诉模板您实际上已经完成了连接,因此无法将其返回到池中。
根据docs,您应该将代码包装在SessionCallback中并使用RedisTemplate.execute(SessionCallback<T> callback)
执行它,这将在您的回调执行后返回到池的连接
像这样:
template.execute(new SessionCallback<List<Object>>() {
public List<Object> execute(RedisOperations operations) throws DataAccessException {
operations.multi();
aMap.put(A_KEY, a.toString(), a);
bMap.put(B_KEY, b.toString(), b);
cMap.put(C_KEY, c.toString(), c);
return operations.exec();
}
});
Spring Data Redis也支持 @Transactional ,它会自动为你绑定/解除绑定连接,但要求你在一个可以拦截的bean中实现该方法(即它可以&#39) ; t是final
),只有从bean外部执行事务才会启动事务(即不是来自同一个类或子/父类中的另一个方法)。
您已经使用redisTemplate.setEnableTransactionSupport(true);
在模板上启用了交易支持,因此您应该好好去:
@Transactional
public void put(A a, B b, C c) {
aMap.put(A_KEY, a.toString(), a);
bMap.put(B_KEY, b.toString(), b);
cMap.put(C_KEY, c.toString(), c);
}