数据库连接数和线程数

前几天开发一个多线程执行的任务,在多线程执行的时候,一直在报错,如下:
An attempt by a client to checkout a Connection has timed out.
com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@29426a4 -- timeout at awaitAvailable()
从异常信息能够看出,是数据库的连接池满了,然而还有新的线程去获取连接池,在获取新连接超过一定时间(用checkoutTimeout配置)后,就会报以上的错误。
 
从网上查到一些遇到相同问题的情况,但是都没真正解决我的问题。
有人说是c3p0在连接使用完毕之后,statement有可能会被缓存,从而导致connection没有真正的关闭掉,当有其他线程获取连接的时候,就获取不到了。但c3p0是默认关闭缓存的,从以下代码可以看出,必须配置maxStatements或maxStatementsPerConnection,若是不配置,它们的默认值都为0,也即不使用用缓存。
if (maxStatements > 0 && maxStatementsPerConnection > 0)
                this.scache = new DoubleMaxStatementCache( taskRunner, deferredStatementDestroyer, maxStatements, maxStatementsPerConnection );
            else if (maxStatementsPerConnection > 0)
                this.scache = new PerConnectionMaxOnlyStatementCache( taskRunner, deferredStatementDestroyer, maxStatementsPerConnection );
            else if (maxStatements > 0)
                this.scache = new GlobalMaxOnlyStatementCache( taskRunner, deferredStatementDestroyer, maxStatements );
            else
                this.scache = null;
 
 
既然是获取新连接超时,那就说明一下几点:
1、连接未正常关闭
2、连接池已经满了
3、线程数比连接数多
4、sql执行慢,占用连接时间长
 
从这几点中,可以分别调整
1、检查程序,是否连接未执行关闭操作
2、调整数据库连接数,但不是连接数越多越好,还得考虑线程数量
3、增加线程休眠时间,或减少线程数,但要保证业务的准确性,线程数可比数据库连接数多,可以综合数据库连接数、获取新连接超时时间(checkoutTimeout)、sql执行时间以及线程休眠时间来大致算出线程数的合适值
4、优化sql,尽量减少sql的执行时间,不要使用大sql,拆分sql执行
5、在获取失败之后,要有重试机制,保证业务正常执行 
6、优化程序和数据库之间的网络
7、适当增加acquireIncrement的值,默认为3
 
最后举个例子
checkoutTimeout配置为3000,也就是超时时间为3000毫秒
maxPoolSize为15,默认值就是15
每个线程执行sql的时间都是10ms,那么同时执行的线程数最好低于4500个=(checkoutTimeout / 10ms) * maxPoolSize 

猜你喜欢

转载自jjhpeopl.iteye.com/blog/2327543