问题以及现象
前一阵子发现redis
断线重连后,会出现类似如下的错误:
解决思路
socket write error
之前以为redisTemplate
不支持断线重连,也就没当回事。后来请教一个比我更有经验的开发人员,他说jedis支持断线重连,并给我写了一个demo,发现确实会断线重连。
但项目上跑的服务为什么不会断线重连呢,接连排除了redis
版本、redisTemplate
版本、redisTemplate
使用不当可能引起的问题,最后在redisTemplate
中发现以下代码:
redisTemplate#execute(RedisCallback<T> , boolean , boolean )
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(action, "Callback object must not be null");
RedisConnectionFactory factory = getConnectionFactory();
RedisConnection conn = null;
try {
if (enableTransactionSupport) {
// only bind resources in case of potential transaction synchronization
conn = RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
} else {
conn = RedisConnectionUtils.getConnection(factory);
}
boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);
RedisConnection connToUse = preProcessConnection(conn, existingConnection);
boolean pipelineStatus = connToUse.isPipelined();
if (pipeline && !pipelineStatus) {
connToUse.openPipeline();
}
RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse));
T result = action.doInRedis(connToExpose);
// close pipeline
if (pipeline && !pipelineStatus) {
connToUse.closePipeline();
}
// TODO: any other connection processing?
return postProcessResult(result, connToUse, existingConnection);
} finally {
if (!enableTransactionSupport) {
RedisConnectionUtils.releaseConnection(conn, factory);
}
}
}
在最后的finally中发现如果启用事务并不会释放连接,猜想可能是这个原因。果然项目上redisTemplate
配置了启用事务这个选项,最后将其去掉,一切回归正常,断线10min后连接仍可以连上。
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="enableTransactionSupport" value="false" />
</bean>
其他
-
redisTemplate
默认不启用事务,如需事务,redisTemplate也提供了手动操作,代码如下:
RedisTemplate redisTemplate = (RedisTemplate) applicationContext.getBean("redisTemplate");
try{
redisTemplate.multi();
......
redisTemplate.exec();
} catch(Exception e){
redisTemplate.discard();
}
- jdk8可以考虑用lettuce,支持同步、异步、哨兵、集群、重连机制,底层用的netty。
网友评论