目录
问题复现:
最近在项目中测试使用redis作为mybatis的二级缓存。
由于我的redis是部署在阿里云服务器上的,造成了redis一直无法获取到连接。
报异常信息如下:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
### Cause: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:82)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy28.findUserById(Unknown Source)
at com.lagou.test.CacheTest.SecondLevelCache(CacheTest.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:50)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:99)
at org.mybatis.caches.redis.RedisCache.execute(RedisCache.java:51)
at org.mybatis.caches.redis.RedisCache.getObject(RedisCache.java:88)
at org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:57)
at org.apache.ibatis.cache.decorators.TransactionalCache.getObject(TransactionalCache.java:68)
at org.apache.ibatis.cache.TransactionalCacheManager.getObject(TransactionalCacheManager.java:35)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:101)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:83)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)
at com.github.pagehelper.SqlUtil._processPage(SqlUtil.java:247)
at com.github.pagehelper.SqlUtil.processPage(SqlUtil.java:229)
at com.github.pagehelper.PageHelper.intercept(PageHelper.java:118)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
at com.sun.proxy.$Proxy27.query(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)
at tk.mybatis.mapper.mapperhelper.MapperInterceptor.intercept(MapperInterceptor.java:61)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
at com.sun.proxy.$Proxy27.query(Unknown Source)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148)
... 29 more
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect timed out
at redis.clients.jedis.Connection.connect(Connection.java:164)
at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:80)
at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1676)
at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:87)
at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:861)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:435)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
at redis.clients.util.Pool.getResource(Pool.java:48)
... 56 more
Caused by: java.net.SocketTimeoutException: connect timed out
at java.base/java.net.PlainSocketImpl.waitForConnect(Native Method)
at java.base/java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:107)
at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.base/java.net.Socket.connect(Socket.java:608)
at redis.clients.jedis.Connection.connect(Connection.java:158)
... 63 more
先上配置文件:redis.properties
redis.host=x.x.x.x redis.port=6379 redis.connectionTimeout=5000 redis.password=xxx redis.database=0
解决方法
先说解决方法:
把redis.properties的配置文件中redis.去掉,运行结果就可以了。
host=x.x.x.x port=6379 connectionTimeout=60000 password=xxx database=0
运行如下:
源码分析
数据库mybatis的配置文件:
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/zdy_mybatis?characterEncoding=utf8 jdbc.username=root jdbc.password=xxxx
我在mybatis的配置文件中开启了二级缓存:
<setting name="cacheEnabled" value="true"/>
并且在mapper.xml文件中指定redis作为二级缓存:
<cache type="org.mybatis.caches.redis.RedisCache" />
并编写好测试代码准备运行:
@Test
public void secondLevelCache(){
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
User user1 = mapper1.findById(1);
sqlSession1.close();
User user2 = mapper2.findById(1);
System.out.println(user1 == user2);
}
发现一直无法获取到redis的链接。报错信息为:org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
经过源码跟踪发现:
创建JedisFactory时并没有获取到我配置的参数,接着往读取配置文件路径的地方跟踪,最终来到RedisConfigurationBuilder的parseConfiguration方法
发现他是正常获取到了我的配置文件路径,那么错误可能不是在这里发生的,证明如下,接着往下跟踪:
如上图,正常获取到了config对象封装起来。那么问题应该就在setConfigProperties这个方法了,
经过debugger发现始终无法进入到 if 判断里面,推测可能是name属性不一致:
于是尝试把了redis.properties配置文件中,redis.的地方删除掉,再次跟踪到这里,发现终于可以进入到if判断了。于是问题得以解决。
最后测试类运行如下: