最近性能測試,並發數上到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也是非線程安全的,再使用的時候一定要謹慎。