为什么要使⽤连接池
⽬的:为了解决建⽴数据库连接耗费资源和时间很多的问题,提⾼性能。 Connection对象在JDBC使⽤的时候就会去创建⼀个对象,使⽤结束以后就会将这个对象给销毁了(close). 每次创建和销毁对象都是耗时操作.需要使⽤连接池对其进⾏优化.程序初始化的时候,初始化多个连接,将多个连接放⼊到池(集合)中.每次获取的时候,都可以直接从连接池 中进⾏获取.使⽤结束以后,将连接归还到池中.
连接池原理:
1. 程序⼀开始就创建⼀定数量的连接,放在⼀个容器中,这个容器称为连接池(相当于碗柜/容器)。
2. 使⽤的时候直接从连接池中取⼀个已经创建好的连接对象。
3. 关闭的时候不是真正关闭连接,⽽是将连接对象再次放回到连接池中。
编写标准的数据源(规范)
Java为数据库连接池提供了公共的接⼝:javax.sql.DataSource,各个⼚商需要让⾃⼰的连接池实现这个接⼝。这样应⽤程序可以⽅便的切换不同⼚商的连接池!
常⻅的第三⽅(⾼性能)连接池如下:
- C3P0开源免费的连接池!⽬前使⽤它的开源项⽬有:Spring、Hibernate等。使⽤C3P0连接池需要导⼊jar包,c3p0使⽤时还需要添加配置⽂件“c3p0-config.xml”
- 功能全⾯的Druid:Druid是阿⾥巴巴开源平台上的⼀个项⽬,整个项⽬由数据库连接池、插件框架和SQL解析器组成。Druid是国内⽬前最好的数据库连接池,在功能、性能、扩展性⽅⾯,都超过其他数据库连接池(包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource)。Druid是阿⾥巴巴开发的号称为监控⽽⽣的数据库连接池!
- 性能⽆敌的HikariCP:HikariCP是由⽇本程序员开源的⼀个数据库连接池组件,代码⾮常轻量,并且速度⾮常的快。根据官⽅提供的数据,在i7,开启32个线程32个连接的情况下,进⾏随机数据库读写操作,HikariCP的速度是现在常⽤的C3P0数据库连接池的数百倍。在SpringBoot2.0中,官⽅也是推荐使⽤HikariCP。
C3P0连接池
C3P0开源免费的连接池!⽬前使⽤它的开源项⽬有:Spring、Hibernate等。使⽤C3P0连接池需要导⼊jar包,c3p0使⽤时还需要添加配置⽂件“c3p0-config.xml”
C3P0连接池⼯具类编写
使⽤步骤
1. 导⼊c3p0-0.9.1.2.jar
2. 拷⻉配置⽂件到src⽬录
3. 创建连接池(配置⽂件⾃动读取的)
- 编写配置⽂件 c3p0-config.xml
<c3p0-config>
<!-- 使⽤默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property
name="jdbcUrl">jdbc:mysql://localhost:3306/day19</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
</default-config>
</c3p0-config>
c3p0连接池常⽤的配置参数:
参数 | 说明 |
initialPoolSize | 初始连接数 |
maxPoolSize | 最⼤连接数 |
checkoutTimeout | 最⼤等待时间 |
maxIdleTime | 最⼤空闲回收时间 |
初始连接数:刚创建好连接池的时候准备的连接数量
最⼤连接数:连接池中最多可以放多少个连接
最⼤等待时间:连接池中没有连接时最⻓等待时间
最⼤空闲回收时间:连接池中的空闲连接多久没有使⽤就会回收
编写Java代码
/**
* C3P0连接池的⼯具类
*
*/
public class C3P0Utils {
//1. 创建⼀个C3P0的连接池对象(会⾃动读取src⽬录下的c3p0-config.xml,所以不需要我们解析配置⽂件)
public static DataSource ds = new ComboPooledDataSource();
//2. 提供 从连接池中 获取连接对象的⽅法
public static Connection getConnection() throws SQLException {
Connection conn = ds.getConnection();
return conn;
}
//3. 提供 获得数据源(连接池对象)的⽅法
public static DataSource getDataSource(){
return ds;
}
}
Druid 连接池
Druid是阿⾥巴巴开发的号称为监控⽽⽣的数据库连接池,Druid是国内⽬前最好的数据库连接池。在功能、性能、扩展性⽅⾯,都超过其他数据库连接池。Druid已经在阿⾥巴巴部署了超过600个应⽤,经过⼀年多⽣产环境⼤规模部署的严苛考验。如:⼀年⼀度的双⼗⼀活动,每年春运的抢⽕⻋票。
Druid的下载地址:https://github.com/alibaba/druid
DRUID连接池使⽤的jar包: druid-1.1.16.jar
Druid连接池⼯具类编写
步骤:
1. 导⼊DRUID jar 包
2. 拷⻉配置⽂件到src⽬录
3. 根据配置⽂件 创建连接池对象
4. 从连接池对象获得连接
实现:
创建druid.properties, 放在src⽬录下
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_wensong?useUnicode=true&characterEncoding=UTF-8&useSSL=false&use&serverTimezone=Asia/Shanghai
username=root
password=root
编写Java代码
/**
* 阿⾥巴巴的连接池 Druid ⼯具类
*/
public class DruidUtils {
/*
1. 加载 druid.properties 配置⽂件
2. 创建 Druid 连接池对象
3. 提供 获得 连接池对象的⽅法
4. 提供 从连接池中 获取连接对象Connection的 ⽅法
*/
public static DataSource ds = null;
static {
try {
//1. 加载 druid.properties 配置⽂件
InputStream is =DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
Properties prop = new Properties();
prop.load(is);
//2. 创建 Druid 连接池对象
ds = DruidDataSourceFactory.createDataSource(prop);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
3. 提供 获得 连接池对象的⽅法
*/
public static DataSource getDataSource(){
return ds;
}
/*
4. 提供 从连接池中 获取连接对象Connection的 ⽅法
*/
public static Connection getConnetion() throws SQLException {
Connection conn = ds.getConnection();
return conn;
}
}
DBUtils
如果只使⽤JDBC进⾏开发,我们会发现冗余代码过多,为了简化JDBC开发,本案例我们讲采⽤apache commons组件⼀个成员:DBUtils。DBUtils就是JDBC的简化开发⼯具包。需要项⽬导⼊commons-dbutils-1.6.jar 才能够正常使⽤DBUtils⼯具。
链接:https://pan.baidu.com/s/18u47P95zzMC1rzCPhUoVhQ 提取码:jg8o
DBUtils是java编程中的数据库操作实⽤⼯具,⼩巧简单实⽤。DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。
Dbutils三个核⼼功能介绍
- QueryRunner中提供对sql语句操作的API.
- ResultSetHandler接⼝,⽤于定义select操作后,怎样封装结果集.
- DbUtils类,它就是⼀个⼯具类,定义了关闭资源与事务处理的⽅法
准备数据
创建表:
create table product(
pid int primary key,
pname varchar(20),
price double,
category_id varchar(32)
);
插⼊表记录
INSERT INTO product(pid,pname,price,category_id) VALUES(1,'联想',5000,'c001');
INSERT INTO product(pid,pname,price,category_id) VALUES(2,'海尔',3000,'c001');
INSERT INTO product(pid,pname,price,category_id) VALUES(3,'雷神',5000,'c001');
INSERT INTO product(pid,pname,price,category_id) VALUES(4,'JACKJONES',800,'c002');
INSERT INTO product(pid,pname,price,category_id) VALUES(5,'真维斯',200,'c002');
INSERT INTO product(pid,pname,price,category_id) VALUES(6,'花花公⼦',440,'c002');
INSERT INTO product(pid,pname,price,category_id) VALUES(7,'劲霸',2000,'c002');
INSERT INTO product(pid,pname,price,category_id) VALUES(8,'⾹奈⼉',800,'c003');
INSERT INTO product(pid,pname,price,category_id) VALUES(9,'相宜本草',200,'c003');
INSERT INTO product(pid,pname,price,category_id) VALUES(10,'⾯霸',5,'c003');
INSERT INTO product(pid,pname,price,category_id) VALUES(11,'好想你枣',56,'c004');
INSERT INTO product(pid,pname,price,category_id) VALUES(12,'⾹飘飘奶茶',1,'c005');
INSERT INTO product(pid,pname,price,category_id) VALUES(13,'果9',1,NULL);
QueryRunner核心类介绍
提供数据源
- 构造⽅法
- QueryRunner(DataSource) 创建核⼼类,并提供数据源,内部⾃⼰维护Connection
- 普通⽅法
- update(String sql , Object ... params) 执⾏DML语句
- query(String sql , ResultSetHandler , Object ... params) 执⾏DQL语句,并将查询结果封装到对象中。
提供连接
- 构造⽅法
- QueryRunner() 创建核⼼类,没有提供数据源,在进⾏具体操作时,需要⼿动提供Connection
- 普通⽅法
- update(Connection conn , String sql , Object ... params) 使⽤提供的Connection,完成DML语句
- query(Connection conn , String sql , ResultSetHandler , Object ...params) 使⽤提供的Connection,执⾏DQL语句,并将查询结果封装到对象中。
QueryRunner实现添加、更新、删除操作
update(String sql, Object... params) ⽤来完成表数据的增加、删除、更新操作
添加
// 插⼊数据
@Test
public void test1() throws SQLException {
//1. 获取 QueryRunnr对象, 这个⽤于执⾏ Sql语句
QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
//2. 执⾏sql代码
String sql = "insert into product values(?,?,?,?)";
int line = qr.update(sql, 14, "康师傅⽅便⾯", 5, "c005");
//3. 处理查询结果数据 ( 如果是插⼊, 更新, 删除操作 没有必要做 步骤3)
System.out.println("line = " + line);
}
更新
// 更新数据
@Test
public void test2() throws SQLException {
//1. 获取 QueryRunnr对象, 这个⽤于执⾏ Sql语句
QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
//2. 执⾏sql代码
String sql = "update product set pname=? , price=? where pid=?";
int line = qr.update(sql, "统⼀⽅便⾯", 4.5, 14);
//3. 处理查询结果数据 ( 如果是插⼊, 更新, 删除操作 没有必要做 步骤3)
System.out.println("line = " + line);
}
删除
// 删除数据
@Test
public void test3() throws SQLException {
QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
String sql = "delete from product where pid = ?";
int line = qr.update(sql, 14);
System.out.println("line = " + line);
}
QueryRunner实现查询操作
query(String sql, ResultSetHandler<T> rsh, Object... params) ⽤来完成表数据的查询操作
ResultSetHandler 结果集
- BeanHandler:将结果集中第⼀条记录封装到⼀个指定的javaBean中。
- BeanListHandler:将结果集中每⼀条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
- ScalarHandler:它是⽤于单数据。例如select count(*) from 表操作。
- ColumnListHandler:将结果集中指定的列的字段值,封装到⼀个List集合中
JavaBean
JavaBean就是⼀个类,在开发中常⽤语封装数据。具有如下特性
1. 需要实现接⼝:java.io.Serializable ,通常实现接⼝这步骤省略了,不会影响程序。
2. 提供私有字段:private 类型 字段名;
3. 提供getter/setter⽅法:
4. 提供⽆参构造
public class Product {
private int pid;
private String pname;
private Double price;
private String category_id;
//省略 getter和setter⽅法
}
BeanHandler
/*
* 查询数据表结果集处理其中⼀种⽅式:
* BeanHandler处理⽅式
* 将数据表的结果集第⼀⾏数据,封装成JavaBean类的对象
* 构造⽅法:
* BeanHandler(Class<T> type)
* 传递⼀个Class类型对象,将结果封装到哪个类的对象呢
* Product类的Class对象
*/
@Test
public void demo01() throws SQLException{
// 通过id查询详情,将查询结果封装到JavaBean product
//1核⼼类
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
//2 sql语句
String sql = "select * from product where pid = ?";
//3 实际参数
Object[] params = {6};
//4 查询并封装
Product product = queryRunner.query(sql, new BeanHandler<Product>(Product.class), params);
System.out.println(product);
}
BeanListHandler
/*
* 查询数据表结果集处理其中⼀种⽅式:
* BeanListHandler处理⽅式
* 将数据表的每⼀⾏数据,封装成JavaBean类对象
* 多⾏数据了,多个JavaBean对象,存储List集合
*/
@Test
public void demo02() throws SQLException{
//查询所有,将每⼀条记录封装到⼀个JavaBean,然后将JavaBean添加到List中,最后返回List,BeanListHandler
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from product";
Object[] params = {};
List<Product> list = queryRunner.query(sql, new
BeanListHandler<Product>(Product.class), params);
for(Product product : list){
System.out.println(product);
}
}
ScalarHander
/*
* 查询数据表结果集处理其中⼀种⽅式:
* ScalarHandler处理⽅式
* 处理单值查询结果,执⾏的select语句后,结果集只有1个
*/
@Test
public void demo03() throws SQLException{
// ScalarHandler : ⽤于处理聚合函数执⾏结果(⼀⾏⼀列)
// * 查询总记录数
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select count(*) from product";
Long obj = queryRunner.query(sql, new ScalarHandler<Long>());
//System.out.println(obj.getClass());
System.out.println(obj);
}
ColumnListHandler
/*
* 查询数据表结果集处理其中⼀种⽅式:
* ColumnListHandler处理⽅式
* 将查询数据表结果集中的某⼀列数据,存储到List集合
* 哪个列不清楚,数据类型也不清楚, List<Object>
* ColumnListHandler构造⽅法
* 空参数: 获取就是数据表的第⼀列
* int参数: 传递列的顺序编号
* String参数: 传递列名
*
* 创建对象,可以加⼊泛型,但是加⼊的数据类型,要和查询的列类型⼀致
*/
@Test
public void demo04() throws SQLException{
// ColumnListHandler : 查询指定⼀列数据
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from product";
List<String> list = queryRunner.query(sql, new ColumnListHandler<String>("pname"));
System.out.println(list);
}
小结
DBUtils⼯具
- 作⽤:简化JDBC的操作
DBUtils常⽤类与⽅法
- QueryRunner构造⽅法
- QueryRunner(DataSource) 创建核⼼类,并提供数据源,内部⾃⼰维护Connection
- QueryRunner() 创建核⼼类,没有提供数据源,在进⾏具体操作时,需要⼿动提供Connection
- QueryRunner ⽤来执⾏SQL语句对象
- update(String sql , Object ... params) 执⾏DML语句
- update(Connection conn, String sql, Object… params) 插⼊表记录、更新表记录、删除表记录
- query(String sql , ResultSetHandler , Object ... params) 执⾏DQL语句,并将查询结果封装到对象中。
- query(Connection conn, String sql, ResultSetHandler handler, Object…params) 查询表记录
- ResultSetHandler 处理结果集的对象
- BeanHandler:将结果集中第⼀条记录封装到⼀个指定的javaBean中。
- BeanHandler<Product>(Product.class) --> Proudct
- BeanListHandler:将结果集中每⼀条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
- BeanListHandler<Product>(Product.class) --> List<Product>
- ScalarHandler:它是⽤于单数据。例如select count(*) from 表操作。
- ScalarHandler<Long>() --> Long
- ColumnListHandler:将结果集中指定的列的字段值,封装到⼀个List集合中
- ColumnListHandler<String>("pname") --> List<String>
- BeanHandler:将结果集中第⼀条记录封装到⼀个指定的javaBean中。