回去认真读了Mybatis源码,发现自己错了,特此更正,以免误导读者,实在是对不起。其实poolMaximumActiveConnections的存在可以正确地限制数据库连接池并发访问数据的连接数,没有问题,之所以我的数据库爆掉了,是我没有正确地维持SqlSessionFactory这个类的一个单例。在使用时一定要保持一个全局唯一的SqlSessionFactory
上次发帖是在跳槽后,今天为止已经在新公司工作了两个星期了,感受什么的,我另外写文章再谈,言归正传,讲正事~~!
目前正在开发一个产品的服务器端代码,持久层我选择了Mybatis3(也就是原来的ibatis)作为框架,之所以选择他理由就是我觉得Hibernate搞起来貌似很复杂,我不太会用,哈哈(上家公司留下的阴影,用Hibernate搞得我想死)。上周完成了大部分代码的开发工作,想着既然是要发布的产品,于是找来Jmeter做压力测试,结果这一测,暴露问题了,mysql返回"
too many connections"这个error,这个error的具体解释参照这个链接
http://dev.mysql.com/doc//refman/5.5/en/too-many-connections.html。
一般持久层与数据库连接都会通过一个连接池(pooled datasource)管理,方便复用连接,控制并发,比较有名的有DBCP,C3P0,BONECP等等。Mybatis3自己实现了一个连接池,在配置文件中指定datasource的type属性为POOLED即可使用。与并发关系较大的两个Mybatis连接池参数是
poolMaximumActiveConnections和
poolMaximumIdleConnections。
好了,出了问题,自然得找文档(官方手册,中英文皆有),poolMaximumActiveConnections是最大的活动连接数,活动连接,顾名思义,就是正在与数据库交互的连接,默认是10,poolMaximumIdleConnections是空闲连接数,就是没有处理请求的连接,默认是5。Mysql的max_connections我设置的是200,既最大连接数。这样一看,好像找不到问题所在,连接池最大的活动连接也就是10,跟200比还差很远,Mysql怎么会返回"too many connections"呢?在查阅文档无果后,我请教周围的一位同事,他虽然没用过Mybatis,但是他说是不是请求数超过poolMaximumActiveConnections后mybatis还会去获取连接,是不是有这样的参数控制,然后让我看看源码,说开源的东西嘛,搞不清楚就看源码。
我一向对源码抱有恐惧的心理,感觉那都是大神写的,我等屌丝怎能看得懂,不过被逼无奈,翻出Mybatis的源码看了一看,结果豁然开朗。找到org.apache.ibatis.datasource.pooled包下面的PooledDataSource类,这个就是连接池的实现类。可以看到里面定义了几个参数,其中就包括poolMaximumActiveConnections和poolMaximumIdleConnections,找到pushConnection方法,这个方法里会判断当前空闲连接数和poolMaximumIdleConnections的大小,如果小于他,会new PooledConnection并放进队列中,这就导致一个问题,当所有的连接被占满后,Mybatis为了保持一定的空闲连接,会不断获取新的连接,然后这些新连接被占用后,就会再去new PooledConnection,结果就是超过了mysql设置的最大连接数,然后数据库返回该错误。不知道这算不算是Mybatis的一个"坑"吧,总之在使用时要小心了,并发量大的时候就会爆掉你的数据库,解决办法很简单,将poolMaximumIdleConnections设置为0即可,果然改掉后压力测试不会爆掉数据库。
现在回想起来,官方文档对poolMaximumIdleConnections的定义是:
在任意时间存在的空闲连接数,完全就解释了这个参数的含义,只不过当时没有仔细想,那这个参数是不是该改名字叫poolPermanentIdleConnections比较好呢,呵呵。
问题解决了,很开心,晚上回去再仔细读下里面的源码,看看还有没有别的没发现的问题。看来源码也不是想象中的那么神秘和高深啊。其实为什么那个同事一下就能看出问题的大概,一方面是经验丰富,另一方面可能与他理解数据库连接池机制有关,归根到底,基础的东西还是最重要的。