数据库连接池
传统JDBC代码
- 缺点:用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、宕机。
解决方案:使用连接池,一次性创建若干链接对象,使用的时候拿出来用,用完毕以后把链接对象放回去连接池。链接对象不够的时候再申请创建若干链接,链接过多的时候把闲置的链接关闭。这样就可以避免每次都创建/关闭链接操作。
数据库连接池编写步骤
- 编写连接池需实现javax.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
Connection getConnection()
Connection getConnection(String username, String password)
在DataSource构造函数中批量创建与数据库的连接,并把创建的连接保存到一个集合对象中
实现getConnection方法,让getConnection方法每次调用时,从集合对象中取一个Connection返回给用户。
当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到连接池的集合对象中,而不要把conn还给数据库。
测试
这样一个简单的链接池就写好了。
问题点:
在使用完毕以后并不是使用Connection来关闭链接,而是使用了链接池类去归还链接对象。已经有点“背离”了JDBC.我们应该实现的是在使用链接完毕以后,依然使用Connection对象调用close方法来达到不关闭,而是归还的链接的目的。
所以要改造conn的close方法
实现思路:
一:继承:放弃,因为Connection接口里边有几十个方法。。。
二:装饰模式:装饰模式可以增强原有行为
三:动态代理:最终实现方案
装饰模式
测试
可以看到,cat的eatting逻辑确实已经改变成了eatting mouse,而不是原来的eatting fish.
动态代理
在Java中使用Proxy创建动态代理对象
修改MyConnectionPool中的getConnection方法,返回的是动态代理对象,而不是最初的conn。
测试
开源数据库链接池
- 现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的实现,即连接池的实现。通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。
- 也有一些开源组织提供了数据源的独立实现:
DBCP 数据库连接池
C3P0 数据库连接池
Apache Tomcat内置的连接池(apache dbcp)
实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。程序员编程时也应尽量使用这些数据源的实现,以提升程序的数据库访问性能
DBCP
- DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:
Commons-dbcp.jar:连接池的实现
Commons-pool.jar:连接池实现的依赖库
- Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。
第一种方式:使用代码创建
第二种方式:使用属性文件,避免硬编码
测试
C3P0 数据源
使用代码
使用配置文件,在类路径根目录中创建c3p0-config.xml文件
测试
配置Tomcat数据源
1.如何为tomcat配置数据源
tomcat/conf/context.xml:文件中配置<Context>配置在这个位置的信息将会被所有的web应用所共享
tomcat/conf/[engin]/[Host]/context.xml文件中可以配置<Context>标签,这里配置的信息将会被这台虚拟主机中的所有web应用所共享
tomcat/conf/server.xml文件中的<Host>标签中配置<Context>标签,这是web应用的第一种配置方式,在这个标签中配置的信息将只对当前web应用起作用
tomcat/conf/[engin]/[Host]/自己创建一个.xml文件,在这个文件中使用<Context>标签配置一个web应用,这是web应用第二种配置方式,在这个<Context>标签中配置的信息将只会对当前web应用起作用
web应用还有第三种配置方式:将web应用直接放置到虚拟主机管理的目录.此时可以在web应用的META-INF文件夹下创建一个context.xml文件,在其中可以写<Context>标签进行配置,这种配置信息将只会对当前web应用起作用
2.在程序中获取这个数据源
想要访问jndi就必须在Servlet中才能执行下列代码:
Context initCtx = new InitialContext();
//固定路径
Context jndi = (Context) initCtx.lookup("java:comp/env");
DataSource source = jndi.lookUp("xiaoka ");
Connection connection = dataSource.getConnection();
System.out.println(connection);