在一年以前使用的java web开发主要使用的框架是ssh框架。相比于自己编写servlet里面的doget()和dopost()方法来说更加的简介高校。然而在学习的时候大都是一个项目小组共同完成一个项目,这就导致了每次都是本机运行,很少测试到并发量导致的相关问题。在我们的项目中当把项目开发出来以后,熬了几天把服务器和项目配置完毕能够在小组成员的测试下完成通过。在周总结上我们兴奋地向大家展示我们的项目成果,当叫大家打开手机输入域名进入我们的项目时就发生了尴尬的事情。有的成员能够进入我们的网站有的则等待很久也没有进去,让我们以为是服务器的带宽或者是其他服务器的问题。刚好那时候在阿里云买了一个linux系统的服务器用作练手(一个月45块钱练手的咱要求不高)。这么low的服务器都能够使用,公司使用的服务器也不至于让20几人同时访问出现问题。貌似在服务器的结果是报错了(具体的错误当时没有保存 大致应该是数据库连接的问题)。后来经过查找资料确定了问题所在,直接连接有弊端使用连接池能够解决问题。
当时的数据库连接代码如下:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver">
</property>
<property name="url" value="jdbc:mysql://localhost:3306/***"></property>
<property name="username" value="****"></property>
<property name="password" value="****"></property>
</bean>
当时是使用hibernate,代码是用myeclipse自动生成的。这里用得很low(建议使用properties文件)。
解决问题后的代码:
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver">
</property>
<property name="url"
value="jdbc:mysql://localhost:3306/**?useUnicode=true&characterEncoding=UTF8"></property>
<property name="username" value="****"></property>
<property name="password" value="***"></property><!-- zhuoqunhubei123 -->
<!-- 初始化连接大小 -->
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="3000" />
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="300" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="10" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="60000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="60" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 开启Druid的监控统计功能 -->
<property name="filters" value="stat" />
<!--<property name="filters" value="mergeStat" /> -->
<!-- Oracle连接是获取字段注释 -->
<property name="connectProperties">
<props>
<prop key="remarksReporting">true</prop>
</props>
</property>
</bean>
这里就解决了人数较多时同时访问的问题。(如果是新手看的话注意啦 需要使用什么得找到相关的jar包放进项目中)
这是相关属性:
配置 | 缺省值 | 说明 |
name | | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:"DataSource-" + System.identityHashCode(this) |
jdbcUrl | | 连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto |
username | | 连接数据库的用户名 |
password | | 连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter |
driverClassName | 根据url自动识别 | 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下) |
initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive | 8 | 最大连接池数量 |
maxIdle | 8 | 已经不再使用,配置了也没效果 |
minIdle | | 最小连接池数量 |
maxWait | | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 |
poolPreparedStatements | false | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 |
maxOpenPreparedStatements | -1 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
validationQuery | | 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。 |
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis | | 有两个含义: 1) Destroy线程会检测连接的间隔时间2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 |
numTestsPerEvictionRun | | 不再使用,一个DruidDataSource只支持一个EvictionRun |
minEvictableIdleTimeMillis | | |
connectionInitSqls | | 物理连接初始化的时候执行的sql |
exceptionSorter | 根据dbType自动识别 | 当数据库抛出一些不可恢复的异常时,抛弃连接 |
filters | | 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall |
proxyFilters | | 类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系 |
外部连接池的比较:
主要功能对比
Druid | BoneCP | DBCP | C3P0 | Proxool | JBoss | Tomcat-Jdbc | |
---|---|---|---|---|---|---|---|
LRU | 是 | 否 | 是 | 否 | 是 | 是 | ? |
PSCache | 是 | 是 | 是 | 是 | 否 | 否 | 是 |
PSCache-Oracle-Optimized | 是 | 否 | 否 | 否 | 否 | 否 | 否 |
ExceptionSorter | 是 | 否 | 否 | 否 | 否 | 是 | 否 |
更新维护 | 是 | 否 | 否 | 否 | 否 | ? | 是 |
下面是通过查询资料得到的关于连接池的作用:
连接池的作用就是为了提高性能。
连接池的作用:连接池是将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对数据库进行访问。这样省略了创建连接和销毁连接的过程。这样性能上得到了提高。
基本原理是这样的:
(1)建立数据库连接池对象(服务器启动)。
(2)按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数)。
(3)对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接。
(4)存取数据库。
(5)关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放入空闲队列中。如实际空闲连接数大于初始空闲连接数则释放连接)。
(6)释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接)。
1 .连接池的概念和为什么要使用连接池?
连接池放了N个Connection对象,本质上放在内存当中,在内存中划出一块缓存对象,应用程序每次从池里获得Connection对象,而不是直接从数据里获得,这样不占用服务器的内存资源。
2 .如果不使用连接池会出现的情况:
a.占用服务器的内存资源
b.导致服务器的速度非常慢
3 .应用连接池的三种方式:
a.自定义连接池
b.使用第三方连接池
c.使用服务器自带的连接池
连接池一般比直接连接更有优越性,因为它提高了性能的同时还保存了宝贵的资源。在整个应用程序的使用过程,当中重复的打开直接连接将导致性能的下降。而池连接只在服务器启动时打开一次,从而消除了这种性能问题。
连接池主要考虑的是性能,每次获取连接和释放连接都有很大的工作量,会对性能有很大影响;而对资源来说起的是反作用,因为保存一定数量的连接是要消耗内存的。应用程序每次从池里获得Connection对象,而不是直接从数据里获得,这样不占用服务器的内存资源。所以一般要建立连接池,而连接的数量要适当,不能太大,太大会过多消耗资源。(所以,考虑2个方面,一个是内存,另一个是资源)。
连接池就是为了避免重复多次的打开数据库连接而造成的性能的下降和系统资源的浪费。