关于数据库连接池和动态数据源的实现、使用对于一个简单的数据库应用,由于数据库的访问不是很频繁。这时可以很简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样就不会带来更多的性能上的开销。但是对于复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。这就意味我们需要去考虑怎样把一个连接多次使用。连接复用,通过建立数据库的连接池以及一套连接使用的管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭给系统带来的开销。外部使用者可以通过getConnection方法获取连接,使用完毕之后再通过releaseConnection方法将连接返回,注意此时的连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。一般的数据库连接池,是使用配置文件在项目启动的使用加载配置文件,根据文件中描述,生成对应的数据库连接池。连接池有许多的属性比如:连接池的初始化连接处、连接池的最大连接数、每次的自增连接数、最大空闲连接数等等数据库连接池技术带来的优势:1.资源重用由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)2.更快的系统响应速度数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用,此时连接的初始化工作均已完成,对于业务处理而言,直接利用现有的可以连接,避免了数据库连接初始化和释放过程的时间开销,从而缩短了系统整体的响应时间。3.统一的连接管理,避免数据库连接泄露在较为完备的数据库连接池实现中可以根据预先的连接占用超时设定,强制回收被占用的连接。从而避免常规数据库连接操作中可能出现的资源泄露。一个数据库连接池的实现1.前言数据库应用,在许多软件系统中经常用到,是开发中大型系统不可缺少的辅助。但如果对数据库资源没有很好地管理(如:没有及时回收数据库的游标(ResultSet)、Statement、连接(Connection)等资源),往往会直接导致系统的稳定。这类不稳定因素,不单单由数据库或者系统本身一方引起,只有系统正式使用后,随着流量、用户的增加,才会逐步显露。在基于Java开发的系统中,JDBC是程序员和数据库打交道的主要途径,提供了完备的数据库操作方法接口。但考虑到规范的适用性,JDBC只提供了最直接的数据库操作规范,对数据库资源管理,如:对物理连接的管理及缓冲,期望第三方应用服务器(ApplicationServer)的提供。下面以JDBC规范为基础,介绍相关的数据库连接池机制,并就如果以简单的方式,实现有效地管理数据库资源介绍相关实现技术。2.连接池技术背景2.1JDBCJDBC是一个规范,遵循JDBC接口规范,各个数据库厂家各自实现自己的驱动程序(Driver),应用在获取数据库连接时,需要以URL的方式指定是那种类型的Driver,在获得特定的连接后,可按照固定的接口操作不同类型的数据库,如:分别获取Statement、执行SQL获得ResultSet等,如下面的例子:在完成数据操作后,还一定要关闭所有涉及到的数据库资源。这虽然对应用程序的逻辑没有任何影响,但是关键的操作。上面是个简单的例子,可以看到在main函数的测试中有调用上面写的close()方法.2.2JDBC连接池在标准JDBC对应用的接口中,并没有提供资源的管理方法。所以,缺省的资源管理由应用自己负责。虽然在JDBC规范中,多次提及资源的关闭/回收及其他的合理运用。但最稳妥的方式,还是为应用提供有效的管理手段。所以,JDBC为第三方应用服务器(ApplicationServer)提供了一个由数据库厂家实现的管理标准接口:连接缓冲(connectionpooling)。引入了连接池(ConnectionPool)的概念,也就是以缓冲池的机制管理数据库的资源。JDBC最常用的资源有三类:—Connection:数据库连接。—Statement:会话声明。—ResultSet:结果集游标。这三个类的关系是一种“爷—父—子”的关系,对Connection的管理,就是对数据库资源的管理。举个例子:如果想确定某个数据库连接(Connection)是否超时,则需要确定其(所有的)子Statement是否超时,同样,需要确定所有相关的ResultSet是否超时;在关闭Connection前,需要关闭所有相关的Statement和ResultSet。因此,连接池(ConnectionPool)所起到的作用,不仅仅简单地管理Connection,还涉及到Statement和ResultSet。2.3连接池(ConnectionPool)与资源管理ConnectionPool以缓冲池的机制,在一定数量上限范围内,控制管理Connection,Statement和ResultSet。任何数据库的资源是有限的,如果被耗尽,则无法获得更多的数据服务。对资源的申请、释放、回收、共享和同步,这些管理是复杂精密的。所以,ConnectionPool另一个功能就是,封装这些操作,为应用提供简单的,甚至是不改变应用风格的调用接口。3.数据源dbcp不管通过什么样的持久化技术,都必须拥有数据连接,在Spring中,数据连接是通过数据源获得的。在Spring中可以通过JNDI获取应用服务器的数据源,也可以直接在Spring容器中配置数据源,此外还可以通过代码的方式创建数据源,便于进行无依赖的单元测试Spring在第三方的依赖包中包含了两个数据源的实现类包:Apache的DBCP和C3p0。可以在Spring的配置文件中利用这两者的任何一个配置数据源DBCP的相关配置beanid=dataSourceclass=org.apache.commons.dbcp.BasicDataSourcedestroy-method=closepropertyname=driverClassNamevalue=com.mysql.jdbc.Driver/propertyname=urlvalue=xxxx/propertyname=usernamevaluexxxx/value/propertypropertyname=passwordvaluexxxxx/value/property/beanBasicDataSource中提供了close()方法关闭数据源,所以必须设定destroy-method=“close”属性,以便Spring容器关闭时,数据源能够正常关闭。出去这几个必要的属性外,还有一些常用的属性,可以在网上去查找一下,也可以在《Spring3.x》8.4(数据源)中找到一个完整的能实现数据源动态切换的数据源配置文件需要生成的目标文件格式已经有了接下来要做的就是动态生成一个数据源的配置文件,并能在Spring容器启动之前生成。从而达到在spring容器启动的时候能正确的为每一个数据库创建独立的连接池。Web项目启动时加载web.xml的顺序首先需要知道的是web.xml的加载过程不会跟节点在文件的相对位置有关系.不会因为filter节点在listener节点之前就先加载filter节点.但是相同的节点之间的加载顺序会依照节点在文件中的相对位置来加载,比如web.xml文件中存在有两个listener节点,加载的时候一定会先加载写在前面的一个监听器1、启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取listener和context-param两个结点。2、紧急着,容创建一个ServletContext(servlet上下文),这个web项目的所有部分都将共享这个上下文。3、容器将context-param转换为键值对,并交给servletContext。4、容器创建listener中的类实例,创建监听器。使用dom4j操作XML文件生成数据源配置文件dom4j是一种解析XML文档的开放源代码XML框架。可以在dom4j的API文档中找到需要使用的各种方法创建一个document对象Documentdocument=DocumentHelper.createDocument();创建一个名为beans的根节点Elementbeans=document.addElement(beans);给beans节点添加属性beans.addAttribute(xmlns,);为节点添加子节点Elementbean=beans.addElement(bean);上面提到的方法,通过组合使用,就能把数据源的配置文件生成为我们最终需要的样子获取得到当前项目的路径this.getClass().getResource(/).toString()Spring根据JdbcTemplate方法名动态设置数据源在Spring中对数据库的操作都使用了在数据源配置文件中配置的JdbcTemplate上面的配置文件中有两个数据源一个是dataSource和dataSourceCrm对应了不同的数据库关键是ID为“dynamicDataSource”的这个bean的设置,它是这个类“com.resourceCenter.utils.DynamicDataSource”的一个实例:Importorg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;publicclassDynamicDataSourceextendsAbstractRoutingDataSource{@OverrideprotectedObjectdetermineCurrentLookupKey(){returnChangeDataSource.getCustomerType();}}DynamicDataSource类继承了Spring的抽象类AbstractRoutingDataSource,而AbstractRoutingDataSource本身实现了javax.sql.DataSource接口(由其父类抽象类AbstractDataSource实现),因此其实际上也是一个标准数据源的实现类。该类是Spring专为多数据源管理而增加的一个接口层它根据一个数据源唯一标识key来寻找已经配置好的数据源队列,它通常是与当前线程绑定在一起的。查看其源码,知道它还实现了Spring的初始化方法类InitializingBean,这个类只有一个方法:afterPropertiesSet(),由Spring在初始化bean完成之后调用(根据该方法名联想应该是设置完所有属性后再调用,实际也是如此):publicvoidafterPropertiesSet(){if(this.targetDataSources==null){thrownewIllegalArgumentException(targetDataSourcesisrequired);}this.resolvedDataSources=newHashMap(this.targetDataSources.size());for(Iteratorit=this.targetDataSources.entrySet().iterator();it.hasNext();){Map.Entryentry=(Map.Entry)it.next();ObjectlookupKey=resolveSpecifiedLookupKey(entry.getKey());DataSourcedataSource=resolveSpecifiedDataSource(entry.getValue());this.resolvedDat