开始前注意点
- 使用的编译器为 eclipse-jee-mars-R-win32-x86_64 Mars 版本为 Release (4.5.0)
- JDK版本 JavaSE-1.8
- druid的Maven版本 1.1.0 https://mvnrepository.com/artifact/com.alibaba/druid/1.1.10
- mysql的版本 5.5.43
- mysql的Maven的版本 5.16 https://mvnrepository.com/artifact/mysql/mysql-connector-java/5.1.6
简介
Druid是阿里巴巴的一个数据库连接池的开源框架,但它不仅用于数据库连接池。它还提供了强大的监控和扩展的功能。
配置项
先介绍下Druid相关的配置项。Druid的配置类为com.alibaba.druid.pool.DruidDataSource。
具体的配置项说明
配置名称 | 默认值 | 说明 |
---|---|---|
name | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:“DataSource-” + System.identityHashCode(this) " jdbcUrl 连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://127.0.0.1:3306/demooracle : jdbc:oracle:thin:@127.0.0.1:1521:demo | |
username | 连接数据库的用户名 | |
password | 连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里 :https://github.com/alibaba/druid/wiki/使用ConfigFilter | |
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 | 有两个含义: 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,是组合关系,并非替换关系 |
常用数据库validationQuery
数据库 | validationQuery |
---|---|
Oracle | select 1 from dual |
MySQL | select 1 |
Microsoft SQL Server | select 1 |
DB2 | select 1 from sysibm.sysdummy1 |
SQLite | select 1 |
HSQLDB | select 1 from INFORMATION_SCHEMA.SYSTEM_USERS |
postgresql | select version() |
ingres | select 1 |
Apache Derby | select 1 |
H2 | select 1 |
Informix | select count(*) from systables |
普通Maven-Java项目实例
下面将以Maven工程的实例来演示Druid的使用
开始前的准备工作
- 数据库 mysql
- 编译器 eclipse
- 创建数据库表
create database demo;
use demo;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`stuCode` varchar(20) DEFAULT NULL,
`username` varchar(20) DEFAULT NULL,
`password` varchar(20) DEFAULT NULL,
`email` varchar(20) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('3', '8020321044', '萨达萨', '123456', '1231@qq.com', '9');
INSERT INTO `student` VALUES ('7', '123123', '52225', '123456', '12312', '5');
实现步骤
- 新建Maven项目DruidDemo
- 配置pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wpx.csdn</groupId>
<artifactId>DruidDemo</artifactId>
<version>1.0.0.RELEASE</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
</project>
- 在src/main/resources 目录下新建名为 db.properties 文件
- 编写properties文件如下(仅供参考):
#Driver
driverClassName=com.mysql.jdbc.Driver
#url
url=jdbc:mysql://localhost:3306/demo
#username
username=root
#password
password=root
#检测数据库链接是否有效,必须配置
validationQuery=SELECT 'x'
#初始连接数
initialSize=3
#最大连接池数量
maxActive=10
#已不用
#maxIdle=20
#配置0,当线程池数量不足,自动补充
minIdle=0
#获取链接超时时间 1 分钟 , 单位为毫秒
maxWait=60000
#获取链接的时候 ,不校验是否可用,开启会有损性能。
testOnBorrow=false
#归还链接到连接池的时候校验链接是否可用
testOnReturn=false
#此项配置为true即可,不影响性能,并且保证安全性。意义为:申请链接的时候检测,如果空闲时间大于
#timeBetweenEvictionRunsMillis,执行validationQuery检测链接是否有效
testWhileIdle=true
#1. Destroy线程会检测连接的间隔时间
#2. testWhileIdle的判断依据
timeBetweenEvictionRunsMillis=60000
#一个链接生存的时间(之前的值:25200000)
minEvictableIdleTimeMillis=300000
#链接使用超时时间限制是否回收
removeAbandoned=true
#超时时间限制时间(单位秒),目前为5分钟,如果有业务处理时间超过5分钟,可以适当调整
removeAbandonedTimeout=300
#链接回收的时候控制台打印信息,测试环境可以加上true,上线环境false。会影响性能
logAbandoned=false
- 编写数据库连接池的工具类,在util包下 编写 DBPoolConnection.java 。代码如下:
package util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.pool.DruidPooledConnection;
public class DBPoolConnection {
private static DBPoolConnection instance = new DBPoolConnection(); //单例模式
private static DruidDataSource druidDataSource = null;
static{
Properties properties = LoadPropertiesFile("db.properties");
try {
druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private DBPoolConnection(){
}
public static DBPoolConnection getInstance(){
return instance;
}
/**
* 获取数据库连接池的连接
* @return DruidPooledConnection 数据库连接
* @throws SQLException
*/
public DruidPooledConnection getConnection() throws SQLException{
return druidDataSource.getConnection();
}
/**
* 关闭数据库连接
* @param conn 数据库连接
* @param ps 预处理的sql语句
* @param rs 结果集
* @throws SQLException
*/
public void closeDB(Connection conn , PreparedStatement ps, ResultSet rs) throws SQLException{
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
}finally{
conn=null;
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
}finally{
ps=null;
}
}
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
}finally{
rs=null;
}
}
}
/**
* 加载配置文件
* @param fileName 配置文件名称
* @return Properties对象
*/
private static Properties LoadPropertiesFile(String fileName){
Properties prop = new Properties();
if(fileName == null || fileName.equals("")){
throw new IllegalArgumentException("Properties file path can not be null ");
}
InputStream in = DBPoolConnection.class.getClassLoader().getResourceAsStream(fileName);
try {
prop.load(in);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(in != null)
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return prop;
}
}
- 在dao包下编写DruidDao.java。执行数据库查询操作,代码如下:
package dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import com.alibaba.druid.pool.DruidPooledConnection;
import util.DBPoolConnection;
public class DruidDao {
private static DBPoolConnection dbp = null;
static{
dbp = DBPoolConnection.getInstance();
}
public static void query(String sql){
DruidPooledConnection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = dbp.getConnection(); //从数据库连接池中获取连接
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount();
while (rs.next()) {
for(int i = 1 ; i <= count; i++){
Object object = rs.getObject(i);
System.out.print(" "+ metaData.getColumnName(i) + " = "+object);
}
System.out.println("");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
dbp.closeDB(conn, ps, rs);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
query("select * from student");
}
}
- 运行结果如下: