Spring RedisConnectionFactory 트랜잭션이 Pool에 연결을 반환하지 않은 다음 소진 시 차단됩니다.
연결 풀을 사용하여 연결 팩토리를 만들기 위한 내 구성입니다.접속 풀이 있습니다.이 코드의 대부분은 스프링스에서 복사한 것입니다.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"
문자열 해시 키와 클래스에서 직렬화된 해시 값 json으로 해시 맵에 매핑A
,B
,그리고.C
각각 다음과 같다.
그것은"A"
->A::toString
->json(A)
마찬가지로B
그리고.C
.
@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);
}
}
기대들
- 연결이 손실되거나 손상된 경우 한 번의 연결만으로 풋 작업이 실행되고 실패해야 합니다.
- Put 작업의 경우 다중 호출 시 연결을 얻고 exec 호출 후 Pool로 돌아갑니다.
- getA 작업의 경우 실행 후 연결이 풀로 반환됩니다.
1개가 효과가 있다는 것을 증명할 수 있는 테스트가 있지만, 조금 회의적이지만 문제는 나머지 2개입니다.디버깅 후 어느 작업을 해도 Pool로 연결이 돌아가지 않아 Pool이 소진되면 차단되는 것을 관찰했습니다.
반환이 시도되었지만 아래의 두 분기가 실패했기 때문에 연결에서 호출되지 않습니다.Taken fromRedisConnectionUtils
// release transactional/read-only and non-transactional/non-bound connections.
// transactional connections for read-only transactions get no synchronizer registered
if (isConnectionTransactional(conn, factory)
&& TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
unbindConnection(factory);
} else if (!isConnectionTransactional(conn, factory)) {
if (log.isDebugEnabled()) {
log.debug("Closing Redis Connection");
}
conn.close();
}
문의사항
- 내가 뭘 잘못하고 있는 거지?
- 연결이 풀에 반환되지 않는 이유는 무엇입니까?
- 연결을 풀로 되돌리려면 어떻게 해야 합니까?
제 생각에 문제는 그 전화가exec()
템플릿에 실제로 연결이 완료되었음을 알려주지 않으므로 풀에 반환할 수 없습니다.
코드를 세션 콜백에 싸서 실행해야 하는 문서에 따라 콜백이 실행된 후에 풀에 연결이 반환되는 세션 콜백을 실행합니다.
다음과 같은 경우:
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을 지원합니다. @Transactional은 연결을 자동으로 바인딩/결합 해제하지만, 이 메서드를 가로챌 수 있는 빈에 구현해야 합니다(즉, 그럴 수 없습니다).final
) 및 거래는 빈 외부에서 실행되는 경우에만 시작됩니다(즉, 동일 클래스 또는 하위/부모 클래스의 다른 메서드에서 실행되지 않음).
을 하도록 하고 하고 템플릿에서 트랜잭션 지원을 이미 활성화하고 .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);
}
언급URL : https://stackoverflow.com/questions/46238811/spring-redisconnectionfactory-with-transaction-not-returning-connection-to-pool
'source' 카테고리의 다른 글
node.js가 'npm start'를 표현하는 앱을 중지하는 방법 (0) | 2023.09.14 |
---|---|
Basic Powershell - Word Docx를 PDF로 일괄 변환 (0) | 2023.09.09 |
Chrome에서 인쇄할 때 href 값을 제거해야 함 (0) | 2023.09.09 |
mpdf에서 css 파일을 추가하는 방법 (0) | 2023.09.09 |
PL/SQL 다중 왼쪽 조인 사용 (0) | 2023.09.09 |