莫名的Executor was closed错误
最近性能测试,并发数上到300的时候,后台就时不时地抛出一些如下的错误:
错误1:Cause: org.apache.ibatis.type.TypeException: JDBC requires that the JdbcType must be specified for all nullable parameters.
错误2:### Cause: org.apache.ibatis.executor.ExecutorException: Executor was closed.
错误3:### Cause: java.lang.NullPointerException
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:8)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:61)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:53)
at org.apache.ibatis.binding.MapperMethod.executeForList(MapperMethod.java:82)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:35)
错误4:### Cause: java.sql.SQLException: You can't operate on a closed Connection!!!
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:8)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:61)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:53)
at org.apache.ibatis.binding.MapperMethod.executeForList(MapperMethod.java:82)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:35)
仔细检查代码,正常情况下不应该抛出这些错误,怀疑是由于连接池数据不够导致的,将weblogic连接池的最大连接数降低为5,然后跑300个并发,连接数不够时,系统会抛出如下的错误:
### Cause: java.sql.SQLException: Internal error: Cannot obtain XAConnection weblogic.common.resourcepool.ResourceDisabledException: Pool CCCDS is Suspended, cannot allocate resources to applications..
at weblogic.common.resourcepool.ResourcePoolImpl.reserveResourceInternal(ResourcePoolImpl.java:377)
at weblogic.common.resourcepool.ResourcePoolImpl.reserveResource(ResourcePoolImpl.java:342)
at weblogic.common.resourcepool.ResourcePoolImpl.reserveResource(ResourcePoolImpl.java:329)
at weblogic.jdbc.common.internal.ConnectionPool.reserve(ConnectionPool.java:417)
或者weblogic会打出log提醒增加pool size,排除连接数不够这个因素。
然后检查weblogic console里关于jdbc connection的设置选项,修改了很多可疑选项都没有效果,后来实在没辙了,换用DBCP连接数据库,仍然报错,说明不是weblogic连接池设置的问题。仔细检查代码,发现DAO类获取Mapper类时有一些问题。
我们使用的是Spring + MyBatis, Spring管理所有的DAO类和他们的基类IBatisDAOSupport,如下是IBatisDAOSupport的代码片段:
1 public class IBatisDAOSupport<T> {
2 private SqlSessionFactory sessionFactory;
3 private T mapper;
4
5
6 public SqlSessionFactory getSessionFactory() {
7 return sessionFactory;
8 }
9
10 public void setSessionFactory(SqlSessionFactory sessionFactory) {
11 this.sessionFactory = sessionFactory;
12 }
13
14 public T getMapper(Class<T> clazz){
15 mapper = getSqlSession().getMapper(clazz);
16 return mapper;
17 }
18
19 protected SqlSession getSqlSession(){
20 return sessionFactory.openSession();
21 }
22 }
问题就出在第15行,试想有2个线程A和B,线程A在调用getMapper时,只是初始化到mapper,然后线程B这个时候占用CPU资源调用getMapper,也初始化了mapper,如果这个时候线程A又获得了CPU,那线程A拿到的mapper类将会是线程B初始化后的类,然后导致后续莫名奇妙的错误。至此,问题解决。
另外,Mybatis的SqlSession也是非线程安全的,再使用的时候一定要谨慎。