大家好,今天我们一起聊聊数据库连接池Druid。
大纲

常用的数据库连接池
Apache Commons DBCP
采用标准的Java EE JDBC API来实现,同时支持JNDI,非常灵活。但是该库的最新稳定版本已经比较老了,而且在高并发场景下性能可能存在问题。
c3p0
功能齐全,能够自动维护连接池,支持JDBC3规范和JDBC2的标准扩展,性能较好。但是配置过于复杂,容易造成资源浪费。
HikariCP
专为高并发场景而设计,性能优越,具有最快的初始化速度和最小的延迟,支持JDBC4 API。但是由于需要更多的JVM资源,可能会造成资源消耗问题。
Tomcat JDBC Pool
由Apache Tomcat的开发人员创建,与Tomcat服务器集成良好,支持高度定制化配置。
Druid
支持JDBC和Oracle驱动程序,全面的性能监测,对等分布式,具有强大的扩展功能和高度定制化配置。
什么是Druid
Druid是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、Proxool等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池,可以说是目前最好的连接池之一。
Druid有什么特点
高效性能
Druid采用了预处理和状态机技术,以及多线程异步IO等技术,使其在高并发、大数据量和大批量请求情况下仍能够保持稳定的高效性能。此外,Druid还具有自适应的连接池缩放功能,可以动态调整连接池大小以满足业务需求,从而避免资源的浪费与瓶颈。
监控和管理
Druid提供了完善的监控和管理功能,通过内置的Web界面可以方便地查看连接池和SQL执行情况,包括连接池的状态、使用情况、线程堆栈、SQL执行时间和执行次数等信息。这些信息可以帮助开发人员及时发现性能问题并进行调优。
安全性
Druid支持IP白名单和黑名单,可以有效地增强数据库的安全防护;同时也支持AES加密算法、密码MD5加密等数据加密技术,以保护数据库的数据安全。
可扩展性
Druid提供了丰富的插件机制,可以按需选择需要的插件进行扩展,包括监控、管理、日志、防火墙、加密等插件,同时也支持自定义扩展,开发者可以根据自身业务情况进行二次开发。
Druid是一个功能强大、性能优异、易于使用、可扩展和可靠的数据库连接池。在实际应用中,它已经被广泛应用于各种高并发、大数据量和大批量请求的业务场景中,并得到了业界的广泛认可和好评。
怎么引入Druid
Druid 0.1.18 之后版本都发布到maven中央仓库中,所以只需在项目的pom.xml中加上dependency就可以。例如:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid-version}</version>
</dependency>
怎么配置Druid
参考配置
DruidDataSource大部分属性参考DBCP的,如果原来使用的DBCP,迁移会很方便。以下为参考配置:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_user}" />
<property name="password" value="${jdbc_password}" />
<property name="filters" value="stat" />
<property name="maxActive" value="20" />
<property name="initialSize" value="1" />
<property name="maxWait" value="6000" />
<property name="minIdle" value="1" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="maxOpenPreparedStatements" value="20" />
<property name="asyncInit" value="true" />
</bean>
配置参数项说明
name
配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。如果没有配置,将会生成一个名字,格式是:”DataSource-” + System.identityHashCode(this). 另外配置此属性至少在1.0.5版本中是不起作用的,强行设置name会出错。
url
连接数据库的url,不同数据库不一样,必须配置参数。例如:
mysql : jdbc:mysql://127.0.0.1:12306/mysqldb
oracle : jdbc:oracle:thin:@127.0.0.1:1521:oracledb
username
连接数据库的用户名,必须配置参数。
password
连接数据库的密码,必须配置参数。如果不希望密码直接写在配置文件中,此处可以配置为加密后的密码密文,在连接数据库时,会先解密为明文再使用。
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下建议关闭。
maxPoolPreparedStatementPerConnectionSize
默认值:-1。要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
validationQuery
用来检测连接是否有效的sql,要求是一个查询语句,常用select ‘x’,重要配置参数。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
validationQueryTimeout
单位:秒,检测连接是否有效的超时时间,重要配置参数。底层调用jdbc Statement对象的void setQueryTimeout(int seconds)方法
testOnBorrow
默认值:true。申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testOnReturn
默认值:false。归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testWhileIdle
默认值:false。建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
keepAlive
默认值:false,1.0.28版本后的参数项。连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作。
timeBetweenEvictionRunsMillis
默认值:1分钟,1.0.14版本后的参数项。有两个含义:1)Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接;2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明。
numTestsPerEvictionRun
默认值:30分钟,1.0.14版本后的参数项。不再使用,一个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日志
log4j配置
<!--druid的日志记录追加器-->
<RollingFile name="druidSqlRollingFile" fileName="./logs/druid-sql.log"
filePattern="logs/$${date:yyyy-MM}/api-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<!--记录druid-sql的记录-->
<logger name="druid.sql.Statement" level="debug" additivity="false">
<appender-ref ref="druidSqlRollingFile"/>
</logger>
<logger name="druid.sql.Statement" level="debug" additivity="false">
<appender-ref ref="druidSqlRollingFile"/>
</logger>
配置慢sql监控
Druid内置提供一个StatFilter,用于统计监控信息。StatFilter的别名是stat,这个别名映射配置信息保存在druid-xxx.jar!/META-INF/druid-filter.properties。
方式一
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
... ...
<property name="filters" value="stat,log4j" />
</bean>
在上面的配置中,StatFilter和Log4jFilter组合使用。
<bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter">
<property name="slowSqlMillis" value="10000" />
<property name="logSlowSql" value="true" />
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
... ...
<property name="filters" value="log4j" />
<property name="proxyFilters">
<list>
<ref bean="stat-filter" />
</list>
</property>
</bean>
别名配置是通过filters属性配置的,filters属性的类型是String。如果需要通过bean的方式配置,使用proxyFilters属性。
其中filters和proxyFilters属性是组合关系的,不是替换的,在上面的配置中,dataSource有了两个Filter,StatFilter和Log4jFilter。以上配置为监控超过10秒的慢sql,根据实际场景调整。
方式二
slowSqlMillis属性也可以通过connectProperties来配置:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
... ...
<property name="filters" value="stat" />
<property name="connectionProperties" value="druid.stat.slowSqlMillis=5000" />
</bean>
配置数据库密码加密
在配置文件中配置数据库密码时,采用明文的方式,密码容易暴露,druid可以采用密码加密的方式。
生成密码密文
数据库密码为123456,采用以下命令生成密码密文及加解密公私钥对。
java -cp druid-1.0.27.jar com.alibaba.druid.filter.config.ConfigTools 123456
privateKey:MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApx1gO8tPiwF+NrMAm0AWYpu+38oiVJ3Y0xaSDpDkcwq/mRLoopRpkXKNnJUjw9GsSCA5FsbyzgbU00gchJBlWQIDAQABAkBCC7UVzKNSL7PfEF2j/e8a56zHK07oHD4uJtRwl0kCQdCJyzn0pKt3AwHgBHtnx4DoKzdj86txx047fCTvpoLRAiEA2SvD6r7cInI8kqbgePzgeFeeVhhjNuXDAAzekBSoKHUCIQDE/nbV9dcsaMBfzcgVpd83rcVUANcVczGnnjshUZRM1QIgPUOTaU2eXDlNzTE2ceskh85v5GnM01fNwt3ei1bIeWECIQCn+b/FREL9mDjpuGPzqaQEK0XHEoxUuwxNPIx5JcIKHQIgICtDfCbr6zA8Tk8jPIxO2p9V5GvoSACh916XQjBpK88=
publicKey:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKcdYDvLT4sBfjazAJtAFmKbvt/KIlSd2NMWkg6Q5HMKv5kS6KKUaZFyjZyVI8PRrEggORbG8s4G1NNIHISQZVkCAwEAAQ==
password:CD5rXr8fgN2pColHLFKR1vWKC/Mps6Lh5luP6BgGVSIaXBk7yscV9z8p9ZDU8R5qEZ2Yn9BDXiM3KyX3kAwvpQ==
DruidDataSource配置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
... ...
<property name="password" value="${datasource.passwd}" />
<property name="filters" value="config" />
<property name="connectionProperties" value="config.decrypt=true;config.decrypt.key=${datasource.key.pub}" />
</bean>
此处的datasource.passwd为生成密码密文时生成的password的值;datasource.key.pub为生成密码密文时生成的publicKey的值。
总结
Druid是一个功能强大、性能优异、易于使用、可扩展和可靠的数据库连接池。在实际应用中,它已经被广泛应用于各种高并发、大数据量和大批量请求的业务场景中,并得到了业界的广泛认可和好评。使用它可以帮我们创建和管理数据库连接,可以使用慢sql等监控功能,使用数据库密码加密等丰富的扩展功能。在选用Druid版本时,应充分了解对应版本出现的问题,评估是否符合应用服务的业务场景。如1.0.9-1.0.25版本,存在当表结构发生变化(新增字段)时,会报java.sql.SQLException: Protocol violation 错误;1.0.27版本,在出现主键冲突后,现有连接池中的链接报iava.sql.sqLRecoverableException:closed statement错误。
原文始发于微信公众号(扬哥手记):一文掌握数据库连接池druid
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/239512.html