欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java开发笔记(一百五十一)Druid连接池的用法

程序员文章站 2022-05-15 14:53:06
C3P0连接池自诞生以来在Java Web领域反响甚好,业已成为hibenate框架推荐的连接池。谁知人红是非多,C3P0在大型应用场合中暴露了越来越多的局限性,包括但不限于下列几点:1、C3P0管理池内连接时没有采取LRU排队规则(最久未使用算法),意味着C3P0未能将数据库性能调到最优。2、在处 ......

c3p0连接池自诞生以来在java web领域反响甚好,业已成为hibenate框架推荐的连接池。谁知人红是非多,c3p0在大型应用场合中暴露了越来越多的局限性,包括但不限于下列几点:
1、c3p0管理池内连接时没有采取lru排队规则(最久未使用算法),意味着c3p0未能将数据库性能调到最优。
2、在处理大批量数据的时候,c3p0对耗时操作过于容忍,致使容易出现线程死锁的状况。
3、c3p0不支持监控功能,外界难以实时跟踪连接池的运行情况,不利于按需分配和调度系统资源。
就上面几点问题的看法因人而异,对老外来说,他们国家人口不多,一百年都难得遇上这种严苛的条件,考虑超大规模的数据处理纯属杞人忧天。但对国人来说,数据库里的业务记录动辄以千万计,亿级以上的海量数据也不罕见,此时一点一滴的性能差距汇总起来就可能出大问题。然而c3p0源自国外,人家才懒得搭理这茬事;再说,此等关键要害岂能由外人扼住咽喉?当然要自己掌握核心技术才让人放心,于是阿里巴巴公司推出了国产的开源连接池druid,该连接池立足于本国国情,在诸多方面加以调整和优化,比c3p0更适用于国内的业务系统。
druid的用法近似于c3p0,它拥有自己的连接池工具druiddatasource,该工具的常见方法列举如下:
setdriverclassname:设置连接池的数据库驱动。
seturl:设置数据库的连接地址。
setusername:设置数据库的用户名。
setpassword:设置数据库的密码。
setinitialsize:设置连接池的初始大小。
setminidle:设置连接池大小的下限。
setmaxactive:设置连接池大小的上限。
setremoveabandoned:设置是否抛弃已超时的连接。
setremoveabandonedtimeout:设置超时的时间间隔,单位秒。如果某连接超过该时间仍未释放,则会被自动回收。
setmaxwait:设置获取连接所允许的等待时间,单位毫秒。超过该时间将不再获取连接。
settimebetweenevictionrunsmillis:设置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒。
setvalidationquery:设置检测连接是否有效的sql语句。
settestwhileidle:当空闲时是否需要进行有效性测试。建议设置为true,保证安全性。
settestonborrow:设置为true,表示申请连接时将调用validationquery方法来检测连接是否有效。
getdbtype:获取数据库的名称。
getactivecount:获取活跃连接的数量。
getconnectcount:获取已连上连接的数量。
getpoolingcount:获取空闲连接的数量。
getconnection:从连接池中获取一个连接,连接类型为druidpooledconnection。
close:关闭连接池。

至于druid的编码过程,则依然分成两个步骤:初始化连接池、从连接池中取出一个连接处理,分别说明如下:
1、初始化连接池
该步骤首先创建druid连接池的对象,再依次调用相关方法设置详细的参数信息,包括数据库驱动、连接地址、用户名、密码,以及与连接池有关的规格参数。下面是初始化druid连接池的代码例子:

	private static druiddatasource datasource; // 声明druid连接池的对象
	// 初始化连接池
	private static void initdatasource() {
		datasource = new druiddatasource(); // 创建druid连接池
		datasource.setdriverclassname(driver_class); // 设置连接池的数据库驱动
		datasource.seturl(dburl); // 设置数据库的连接地址
		datasource.setusername(dbusername); // 设置数据库的用户名
		datasource.setpassword(dbpassword); // 设置数据库的密码
		datasource.setinitialsize(1); // 设置连接池的初始大小
		datasource.setminidle(1); // 设置连接池大小的下限
		datasource.setmaxactive(20); // 设置连接池大小的上限
	}

  

2、从连接池中取出一个连接处理
注意该步骤的getconnection方法拿到的是druidpooledconnection类型的连接对象,再根据该连接创建对应的报告,并开展后续的数据库操作。为方便观察连接池的运行情况,可在其中添加几个连接池的检测方法,例如getactivecount、getconnectcount、getpoolingcount等等。修改后的数据库操作代码示例如下:

	// 显示性别分组
	private static void showrecordgroupbysex() {
		string sql = "select sex,count(1) count from teacher group by sex order by sex asc";
		// 从连接池中获取连接、创建连接的报告、命令报告执行指定的sql语句
		try (druidpooledconnection conn = datasource.getconnection();
				statement stmt = conn.createstatement();
				resultset rs = stmt.executequery(sql)) {
			while (rs.next()) { // 循环遍历结果集里面的所有记录
				int sex = rs.getint("sex"); // 获取指定字段的整型值
				int count = rs.getint("count"); // 获取指定字段的整型值
				string desc = string.format("%s老师有%d位;", sex==0 ? "男" : "女", count);
				system.out.print(desc);
			}
			system.out.println("\ngetactivecount="+datasource.getactivecount()); // 获取活跃连接的数量
			system.out.println("getconnectcount="+datasource.getconnectcount()); // 获取已连上连接的数量
			system.out.println("getpoolingcount="+datasource.getpoolingcount()); // 获取空闲连接的数量
		} catch (sqlexception e) {
			e.printstacktrace();
		}
	}

 

然后由外部反复调用以上的showrecordgroupbysex方法,假设准备测试连续的三次数据库操作,则外部的调用代码如下所示:

		for (int i=0; i<3; i++) { // 多次操作数据库
			showrecordgroupbysex(); // 显示性别分组
		}

 

运行包含上面代码的测试程序,观察到下面的输出日志:

男老师有2位;女老师有3位;
getactivecount=1
getconnectcount=1
getpoolingcount=0
男老师有2位;女老师有3位;
getactivecount=1
getconnectcount=2
getpoolingcount=0
男老师有2位;女老师有3位;
getactivecount=1
getconnectcount=3
getpoolingcount=0

 

由日志可见,getactivecount方法返回了当前正在使用的连接数量,getconnectcount方法返回了曾经连上与已经连上的连接总数,getpoolingcount返回了连接池中剩余的连接数量。



更多java技术文章参见《java开发笔记(序)章节目录