大约在半年前,曾经帮同事解决过一个Commons-dbcp连接池的问题。当时遇到的问题比较诡异,但是其实并不是什么特别复杂的问题,了解DBCP的原理,大部分问题就迎刃而解了。本文主要对连接池的基本原理以及dbcp的实现方式做一个分析,对dbcp的配置参数结合原理做一个简单解释。
连接池扼要
JDBC是一套通用的Java语言与多种数据库(文件)通讯的标准API。大部分针对数据库服务器(例如Oracle, MySQL等等)的JDBC实现都是基于TCP/IP连接的客户端-服务器端通讯方式。
当我们需要执行一个数据库操作时,有下面三步:
- 客户端与服务器之间建立一个数据库连接
- 执行某种数据库操作
- 断开连接
如果每次处理都要走上面的三步,则应用程序与数据库服务器都要将大量的时间和资源消耗在数据连接的断开与建立上。对于某些数据库系统,一个数据库连接就是一个进程,而且数据库连接通常要占用不少资源,如排序区/Join区等等。对于并发较大的系统,建立一次连接然后缓存起来连续使用,直到程序结束等情况下再释放连接,就能够将系统资源集中在对数据库操作的处理上,从而大大提高性能。通常情况下将数据连接的建立和断开委托给一种能够数据库连接池的组件或服务进行管理。而DBCP, C3p0, Proxool等都是常用的开源的连接池组件。
就好像A公司在郊外,他们公司附近没有出租车。如果A公司有人要出去办事,他必须打电话给出租公司订车,用完车后他还要付账报销。 这样每个人出去一趟都必须订车、退车和报销。员工的很多时间白白花费在这上面了。于是A公司跟出租车公司定了一个合同,出租车公司给了他们一个车队。要用车随时去楼下找车队就可以了,用完了也不必结帐,A公司统一跟出租车公司订车和结帐。这个车队就好比连接池,由公司(应用程序)来统一向出租车公司(数据库服务器)订车(建立连接)和退车(关闭连接)。
DBCP的配置参数以及背后的原理
Commons-dbcp连接池的配置参数比较多,也比较复杂,主要分为
- Jdbc连接参数(username, password, url, driverClassName, connectionProperties )
- 事务处理参数 (defaultAutoCommit, defaultReadOnly, defaultTransactionIsolation, defaultCatalog)
- 连接池参数(详见下文)
- 连接池中链接存活性测试参数(详见下文)
- 预处理查询池化参数(poolPreparedStatements, maxOpenPreparedStatements)
- 丢弃失效链接相关参数(详见下文)以及一个控制是否可以正常情况下处于访问连接池包装下的底层JDBC链接参数(accessToUnderlyingConnectionAllowed)
其中Jdbc链接参数、事务处理都跟连接池关系不大,另预处理查询池化参数本文不详细叙述。有关commons-dbcp的详细参数配置信息请参考官方文档。
连接池的配置
再用车队来比喻,出租车公司每提供一辆车给A公司,A公司肯定要付出一定费用。这时候维持车队的大小就很重要了,在项目少用车少的时候,车队肯定要减少,不然很多空闲车辆也要付出成本;在项目多用车多的时候,肯定要扩大车队,不然车不够用,车队忙不过来。A公司可以简单地设地两个阀值来动态调节车队中空闲的车辆数目以满足动态需求,一个是最小空闲车辆数(最小空空闲连接数(minIdle),当剩余的空车数目小于该数目时,A公司就向出租车公司请求加入新车。 一个是最大空闲车辆数(maxIdle),当剩余的车大于该数目时,就将刚刚用用完的车还给出租车公司从而减少车队数量。
另外,这家出租车公司可能要为多个客户服务,要考虑能够提供给A公司的最大的车数量,不能超过某个数量(maxActive)。所以A公司想出租车申请新车时首先要看下当前正在用的车辆数目是否超过了这个最大数目,如果没有超过那就直接申请新车,否则可以让申请者(应用程序中执行请求的线程)等待 (maxWait<=0, 无限等待; maxWait>0 当等待时间超过 maxWait时,失败)。
在连接池中,这几个参数是十分重要的,官方的说明如下,是我们调节系统性能时需要认真考虑的值。
Parameter |
Default |
Description |
| initialSize |
0 |
The initial number of connections that are created when the pool is started. Since: 1.2 线程池启动时初始化的连接数
|
| maxActive |
8 |
The maximum number of active connections that can be allocated from this pool at the same time, or non-positive for no limit. 最大活动连接数,如果非正整数,则不做限制。
|
| maxIdle |
8 |
The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit. 最大空闲连接数。
|
| minIdle |
0 |
The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none. 最小空闲连接数。
|
| maxWait |
indefinitely |
The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception, or -1 to wait indefinitely. (在没有连接可用时)连接池等待一个数据连接可用时的以毫秒计的最大等待时间,超时以后抛出异常, -1 则将无限等待
|
实际上,Dbcp 依赖于 commons-pool 来存储连接对象。 BasicDataSource默认使用GenericObjectPool来管理连接对象。除了请求的线程会在请求和返回连接过程中影响池中连接实例外,另有一个跑着GenericObjectPool.Evictor类型 (implements Runnable) 的实例的线程,也会影响池中的数据库连接。
请继续阅读下一篇:《DBCP连接池(二):Commons-pool的设计》
以前只知道日本右翼历史教科书是怎么篡改历史的,最近读到袁伟时先生的这篇文章,我深受震动,原来我们的历史教科书也有问题。 我们自小接受的历史教育里竟然也有对历史的裁剪、修改,给我们对中国近代历史的认识造成了太严重的影响。影响有多严重,列个提纲各位看官就知道了:
- 火烧圆明园是无法避免的? (看过这个问题你会明白第二次鸦片战争中中方对于战争的起因、过程和结果都负有重要责任)
- (义和团)是爱国壮举还是摧残文明和反人道的罪行 (看过这个问题,你会明白义和团的罪恶和八国联军侵占北京不只是对方的责任。 两国交战不杀来使在中国历史上早已认知,要是随意杀死对方的民众就更不应该了,这一段历史教科书里对史实的篡改实在是太糟糕了。在我们记恨南京屠杀时,也想想我们的清政府和义和团所犯下的杀戮。)

初中历史教科书图片(本图片不代表袁伟时文章中批判的教材,袁文可能指的是别的版本)
我们的心中积累了太多的仇恨和屈辱,认真对待这一百多年的近代历史,对我们的世界观异常重要。毫无疑问,帝国主义在中国领土上犯下了罪行,但是正确地认知这一进程中的真相,认识到我们的国家在这个转变过程中所经历的曲折、所犯下的错误和之所以这样的原因,或许我们能原谅清朝当政者为何犯下愚昧的错误,理解义和团先民为何会去破坏铁路、会去杀无辜的教民,明白为何赞叹夏宫的英法要烧毁圆明园、为何八国联军杀进北京最后却用庚子赔款做一些有益于中国民族进步的事情,还原一个真实的历史,才能让我们有一个正常的、自信的、健全的世界观。
再引一段吧:
19、20世纪中国人干了不少“无法无天”的事,义和团事件是其中的典型。值得重视的是不但至今有人把野蛮的行为说成是“革命”,而且到了20世纪90年代,有人竟把主张遵守现行国际条约的观点视为应该严加批判的卖国投降观点!
这篇文章或许是因为其真实而对国人的思想产生强大的震撼,直接导致了刊登该文的杂志主编被撤职,杂志停刊。
2006年1月11日“中国青年报”的《冰点》周刊因刊出袁伟时文章《现代化与历史教科书》[2],因而导致暂时停刊,并引致主编李大同及副主编卢跃刚撤职。3月1日《冰点》复刊,刊登张海鹏的《反帝反封建是近代中国历史的主题》文章批驳上文,并拒刊袁伟时《为何、何时、如何反帝反封建》文章。(来源:维基百科)
也许有的读者会质疑袁伟时的观点,那太好了,希望有人出来反驳一下,真理越辩越明。
下面给出两个版本的链接,内容大致是一样的,只是青年报的版本用语可能更谨慎些。同时放在这里是为了降低因墙影响不能阅读的概率。
文章链接:
上初中的时候,因为舅舅、叔叔他们都特别喜欢卓依婷,我听得最多的歌声差不多也是卓依婷的,于是渐渐喜欢上了她的歌声。初高中的时候就听舅舅说她已经因为车祸离世了,感到十分惋惜。
后来我把我们家人对于卓依婷的热爱,以及她已经离世等等都告诉了老婆。才知道她也是喜欢卓依婷的歌的。不过这两天听了三四个人演唱的《小城故事》,觉得都和原唱有一定的差距。而卓依婷估计唱这个歌的时候年纪还很小,歌声有些区别也是可以理解的。
于是我顺便Google了一下有关卓依婷的资料,没想到发现搜索提示框里排名第二的是”卓依婷之死“,于是搜索进去,结果大吃一惊,原来她并没有去世。各种消息都是以讹传讹吧。老婆说,他应该把这个消息告诉我舅舅和叔叔,他们也应该会感到高兴的,因为可以买新专辑了
。
她只是中间休息了两年(她81年出生,我想休息一下学学东西也是好的),但是2001年复出后没有很特别的成果,加上个人低调等原因,有关她的消息不是特别多。可能这些年努力也不容易,她之前给人民的主要印象还是年少时的作品,如今好些年了,要转变也不是一个容易的事情。祝她顺利。
顺便去看了看她的博客,觉得很平易近人,有一种很亲切的感觉。
另外,她现在签约优格音乐文化有限公司,暂时不知道该公司的更多资料。她还开通了官方网站。
有的情况下需要在进程之间实现互斥,这对于普通Java程序来说,因为是运行在虚拟机里的原因,手段远不如原生程序方便,但是也有一些简单的方法可以做到。第一个就是使用Socket监听某个端口,第二种方法是使用文件锁定。
使用Socket实现进程互斥
因为Java服务器套接字都是基于系统的socket接口实现的,而socket接口会保证一个套接字端点在整个系统中是唯一的,所以只需要在应用启动时监听一个端口,就可以让系统不同时启动。虽然方法比较土,但是也能用。
try {
ServerSocket ss = new ServerSocket(3030);
}catch (Exception e) {
logger.error("Cannot start", e.printStackTrace());
System.exit();
}
使用文件锁在进程间同步
另一个实现Java进程间互斥的方法,就是文件锁。不过与上面使用套接字不同,使用文件锁还可以实现更高级的互斥/协作。完全可以用文件锁来实现不同Java进程之间的同步,基本思路与在线程之间使用读写锁同步相似。
JDK本身直接支持文件锁,在FileChannel下有几个与文件锁有关的方法,可以打开一个FileLock对象。当调用FileLock#release()方法,或者Channel关闭,或者JVM退出时都会释放该锁。文件锁是JVM全局的,与Java内部的锁/线程等无关,是进程之间的竞争关系。如果你不想发生意外你的程序挂起,那就应该用FileChannel#trylock,而不是直接使用FileChannel#lock(),这样在不能加锁时可以休眠一段时间再等等,或者超时退出。
文件锁像读写锁一样,可以是加共享锁,也可以加独占锁,还可以给锁定限制范围。这是操作系统本身提供的功能,JDK在操作系统层面上做了封装。在Linux下,其实就是调用fcntl来设置相关的状态。如下面的代码,会给文件加独占锁,如果再起新的进程,进程就会打开文件失败退出。
char* lockfile;
int lockfd;
struct flock lock;
time_t t;
if ((lockfd = open(lockfile, O_RDWR)) == -1) {
fprintf(stdout, "open file %s fail: %s \n", lockfile, strerror(errno));
exit(1);
}
t = time(NULL);
lock.l_type = F_WRLCK;
lock.l_start = 0;
lock.l_len = 0;
lock.l_whence = SEEK_SET;
if (fcntl(lockfd, F_SETLKW, &lock) == -1) {
fprintf(stdout, "lock file %s fail: %s \n", lockfile, strerror(errno));
}
fprintf(stdout, "lock file %s success(%d): %ld \n", lockfile, (int)getpid(), time(NULL)-t);
sleep(30);

Update(2010-12-01):爱是永不止息。祈愿她能度过难关求得新生。另,不久前我家小女儿出生了,我也做了爸爸。补一张出生两天多时的照片。爱是永不止息。
Update(2010-3-18): 小怡凡在各界爱心人士的帮助下终于踏上了去往美国医疗的路程。详情在拯救小怡凡主页上。 还要担心手术会怎样,真心祈愿她早日康复!
从小怡凡的主页上了解到:第一,如果要孩子一定要让自己身体健康、强壮;第二,如果孩子有不好,要提早治疗,找几家医院或许能相互参考。
2010年1月19日亚历山大医生带回来怡帆的血样检测及影像分析结果,排除了由DNA变异导致的先天性肺疾病, 确切的病症是”肺细胞代谢缺陷”,肺间质形成脂肪蛋白阻碍氧气进入血液交换,这正是肺部影像一直呈现毛玻璃状的真正原因, 由此导致左心室向肺部加速血液输送,形成“肺动脉高压”。北京市儿童医院2006年对怡帆实施过两次“肺灌洗”, 灌洗液培养结果未见蛋白成分,后归结于“肺纤维化”。几年来,未能及时对症治疗和控制肺间质的脂肪蛋白生长, 错过了治疗及手术修复的最佳时机,目前必须通过全肺移植来救治。
由于我的工作性质以及之前努力工作却忽视了身体,我有些担心我家小宝贝,祈祷他/她在妈妈肚子里健康孕育、成长!
===============================================================================
下面是一个患病需要高昂费用去救助的孩子,他的爸爸妈妈只有一年多点的时间来筹集500,000$,人民币是350万。病情越来越严重了,时间快到了,可是却还不一定能够攒足这笔费用。我老婆看了小孩的照片和故事,心疼不已。我看着也心疼。只可惜我经济状况也不好,只能提供一点捐款。在这里贴下小怡帆的照片,希望过往的人们看到,伸出援助之手。在为小怡帆祈祷的同时,也祈愿天下的小孩子都健康活泼。

很感谢您能抽时间了解怡帆的事情,怡帆是我四岁的女儿,患有肺动脉高压,需要二十四小时吸氧来维持呼吸, 北京儿童医院诊断为肺纤维化,国内无法医治。在和睦家医院亚历山大医生的全力帮助下, 怡帆有机会去美国德州儿童医院接受心肺移植手术,费用十分昂贵,作为孩子的父母, 我们没有足够的时间来积累这笔费用,为此,和睦家基金会帮助我们建立了怡帆基金,寻求社会的帮助, 请您抽出少量的时间浏览www.yifanfund.com和 www.help-yifan.org, 同时将这个网站告诉您周围的朋友,并恳请提供一些帮助来挽救这个孩子。谢谢!
上面的话来自怡帆的父亲,我们的朋友潘俊廷。
详细请去救助小怡帆的主页。
Recent Comments