文章目录
1 连接池
1.1 连接池概述
Connection对象在JDBC使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了(close).每次创建和销毁对象都是耗时操作.需要使用连接池对其进行优化.
为了解决建立数据库连接耗费资源和时间很多的问题
1.2 连接池原理
- 程序一开始就创建一定数量的连接,放在一个容器中,这个容器称为连接池(相当于碗柜/容器)。
- 使用的时候直接从连接池中取一个已经创建好的连接对象。
- 关闭的时候不是真正关闭连接,而是将连接对象再次放回到连接池中。
1.3 常见第三方连接池
面向接口编程:
Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!
- C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。C3P0是异步操作的,所以一些操作时间过长的JDBC通过其它的辅助线程完成。目前使用它的开源项目有Hibernate,Spring等。C3P0有自动回收空闲连接功能
- 阿里巴巴-德鲁伊druid连接池:Druid是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和SQL解析器组成。该项目主要是为了扩展JDBC的一些限制,可以让程序员实现一些特殊的需求。
- DBCP(DataBase Connection Pool)数据库连接池,是Apache上的一个Java连接池项目,也是Tomcat使用的连接池组件。dbcp没有自动回收空闲连接的功能。(已经过时抛弃)
1.4 C3P0连接池
C3P0开源免费的连接池!目前使用它的开源项目有:Spring、Hibernate等。使用C3P0连接池需要导入jar包,c3p0使用时还需要添加配置文件“c3p0-config.xml”
* C3p0连接池的使用
* 开发人员来说: 从连接池中,拿连接使用
* 肯定实现接口 DataSource
*
* 使用步骤:
* 1: 导入jar包
* 2: 连接数据库的4大信息为必须有
* 配置文件中(固定位置、固定名称)
* A: 文件名字 c3p0-config.xml
* B: 文件放在src下
*
* 3: 创建出DataSource接口实现类
* 实现类方法Connection getConnection() 获取连接使用
2 编写配置文件 c3p0-config.xml
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydatabase</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
</default-config>
</c3p0-config>
c3p0连接池常用的配置参数:
c3p0连接池常用的配置参数:
参数 | 说明 |
---|---|
initialPoolSize | 初始连接数 |
maxPoolSize | 最大连接数 |
checkoutTimeout | 最大等待时间 |
maxIdleTime | 最大空闲回收时间 |
初始连接数
:刚创建好连接池的时候准备的连接数量
最大连接数
:连接池中最多可以放多少个连接
最大等待时间
:连接池中没有连接时最长等待时间
最大空闲回收时间
:连接池中的空闲连接多久没有使用就会回收
3 使用厂商提供的DataSource接口实现类,创建连接池
public class C3P0Utils {
//3: 创建出DataSource接口实现类的对象
/**
* 类C3p0Utils只要进入内存,加载静态成员
* 创建接口DataSource的实现类对象new ComboPooledDataSource()
* 实现类对象,会自动读取配置文件!!
*/
private static DataSource dataSource = new ComboPooledDataSource();
//提供方法,返回连接对象
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//定义方法,获取DataSource接口实现类
public static DataSource getDataSource(){
return dataSource;
}
}
1.5 Druid 连接池
Druid是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是国内目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。如:一年一度的双十一活动,每年春运的抢火车票。
Druid的下载地址:https://github.com/alibaba/druid
DRUID连接池使用的jar包:druid-1.1.16.jar
* 阿里巴巴的连接池 Druid 德鲁伊连接池
* 目的: 从连接池中取出连接
*
* 实现步骤:
* 1: 导入jar包
* 2: 创建druid.properties, 放在src目录下(数据库连接的四大要素)
* 对比C3P0的配置文件名字任意,存储位置任意
* 我们自己读取配置文件的内容
*
* 3: 创建DataSource接口实现类
* 实现类的方法 getConnection()获取连接
1 编写druid.properties的配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydatabase
username=root
password=root
2 使用厂商提供的DataSource接口实现类,创建连接池
public class DruidUtils {
//创建DataSource接口变量
private static DataSource dataSource ;
static {
try {
//自己读取配置文件
InputStream inputStream = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
//流中的数据,存储在集合中
Properties properties = new Properties();
properties.load(inputStream);
//3: 创建DataSource接口实现类
//设计模式,工厂设计模式,通过工厂类获取对象
//工厂类获取 接口 DataSource对象
//DruidDataSourceFactory方法.createDataSource()
//日历类; Calendar c = Calendar.getInstance();
dataSource = DruidDataSourceFactory.createDataSource(properties);
}catch (Exception ex){
ex.printStackTrace();
}
}
//定义方法,获取连接对象
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//定义方法,获取DataSource接口实现类
public static DataSource getDataSource(){
return dataSource;
}
}
2 DBUtils
如果只使用JDBC进行开发,我们会发现冗余代码过多,为了简化JDBC开发,本案例我们讲采用apache commons组件一个成员:DBUtils。
DBUtils就是JDBC的简化开发工具包。需要项目导入commons-dbutils-1.6.jar
才能够正常使用DBUtils工具。
2.1 DBUtils概述
DBUtils是java编程中的数据库操作实用工具,小巧简单实用。DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。
Dbutils三个核心功能介绍
- QueryRunner中提供对sql语句操作的API.
- ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
- DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法
2.2 QueryRunner核心类介绍
A 提供连接
- 构造方法
QueryRunner()
创建核心类,提供无参构造方法
- 普通方法
update(Connection conn , String sql , Object ... params)
使用提供的Connection,完成DML语句query(Connection conn , String sql , ResultSetHandler , Object ... params)
使用提供的Connection,执行DQL语句,并将查询结果封装到对象中。
B 提供数据源DataSource
- 构造方法
QueryRunner(DataSource)
创建核心类,并提供数据源,内部自己维护Connection
- 普通方法
update(String sql , Object ... params)
执行DML语句query(String sql , ResultSetHandler , Object ... params)
执行DQL语句,并将查询结果封装到对象中。
2.2.1 QueryRunner实现添加、更新、删除操作
update(Connection conn , String sql , Object ... params)
使用提供的Connection,完成DML语句
/**
* 使用DBUtils工具类,实现数据的 insert,update,delete
* 核心类 QueryRunner执行SQL语句
* 1: 创建对象
* 无参数构造,直接new
* QueryRunner(DataSource ds) 传递DataSource接口实现类的对象
* c3p0,druid 自己从连接池中取连接
*
* 2: 调用方法update
* int update(Connection conn, String sql, Object... params)
* conn连接对象
* sql SQL语句
* params SQL语句中的问号占位符
*
Execute an SQL INSERT, UPDATE, or DELETE query.
*/
public class DBUtilsDemo {
public static void main(String[] args) throws SQLException {
delete();
}
/**
* 实现删除数据
*/
public static void delete()throws SQLException{
//创建QueryRunner的对象
QueryRunner qr = new QueryRunner();
//删除的SQL
String sql = "delete from product where pid = ?";
//参数,直接传递主键
int row = qr.update(DruidUtils.getConnection(), sql, 14);
System.out.println(row);
}
/**
* 实现更新数据
*/
public static void update()throws SQLException{
//创建QueryRunner的对象
QueryRunner qr = new QueryRunner();
//拼写update语句
String sql = "update product set pname = ? , price = ? ,category_id = ? where pid = ?";
//问号中参数,定义在数组中
Object[] params = {"老年机",199,"c001",15};
//update方法执行SQL
int row = qr.update(DruidUtils.getConnection(), sql, params);
System.out.println(row);
}
/**
* 实现数据的添加
*/
public static void insert()throws SQLException{
//创建QueryRunner的对象
QueryRunner qr = new QueryRunner();
//拼写添加数据的SQL
String sql = "insert into product values(?,?,?,?)";
//执行update方法
//传递数据库连接对象,c3p0,druid
//SQL语句中参数,存储在数组,代码可读性,维护性提高
Object[] params = {null,"8848手机",1898,"c001"};
int row = qr.update(DruidUtils.getConnection(),sql,params);
System.out.println(row);
}
}
2.2.2 QueryRunner实现查询操作
query(String sql, ResultSetHandler<T> rsh, Object... params)
用来完成表数据的查询操作
ResultSetHandler 结果集
- BeanHandler:将结果集中第一条记录封装到一个指定的javaBean中。
- BeanListHandler:将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
- ScalarHandler:它是用于单数据。例如select count(*) from 表操作。
- ColumnListHandler:将结果集中指定的列的字段值,封装到一个List集合中
JavaBean
JavaBean就是一个类,在开发中常用语封装数据。具有如下特性
- 需要实现接口:java.io.Serializable ,通常实现接口这步骤省略了,不会影响程序。
- 提供私有字段:private 类型 字段名;
- 提供getter/setter方法:
- 提供无参构造
import lombok.Data;
import java.io.Serializable;
/**
* 一个类包含私有成员变量,包含get/set方法,包含无参数构造
* 称为JavaBean对象
* 应该可以被序列化 (目前省略)
*/
@Data
public class Product {
private int pid ;
private String pname ;
private double price ;
private String category_id ;
}
实例:
/**
* 实现查询
* 1: QueryRunner构造方法
* QueryRunner(DataSource ds) 传递接口实现类
* 接口的实现类,数据源,连接池
* QueryRunner自动从连接池取出连接使用
*
* 2: JavaBean对象
* 一个类包含私有成员变量,包含get/set方法,包含无参数构造
* 称为JavaBean对象
*
* QueryRunner类的方法 query执行查询 Select语句
* query(String sql, ResultSetHandler<T> rsh, Object... params)
* 参数 sql :传递执行的select语句
* 参数 rsh: 是接口ResultSetHandler的实现类对象
* ResultSetHandler:表示的是查询后的结果集
* 接口实现类:
* BeanHandler : 查询数据表的第一行数据,存储到JavaBean对象
* BeanListHandler : 查询数据表,数据的每一行存储到JavaBean对象,多个JavaBean对象,存储到List集合
* ColumnListHandler : 查询数据表中的一个列的数据,存储到List集合
* ScalarHandler : 适合单值查询,结果集只有一个值 count(*)
*
*
* 参数params: SQL语句中问号占位符参数
*
*/
public class DBUtilsDemo02 {
public static void main(String[] args) throws SQLException {
scalarHandler();
}
/**
* ScalarHandler : 适合单值查询,结果集只有一个值 count(*)
* 查询的结果集只有一个值,例如聚合函数 avg max min sum
* select pname from product where pid = 1;
*/
public static void scalarHandler()throws SQLException{
//创建QueryRunner对象,构造方法,传递DataSource接口实现类
QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
//查询表中共有多少条数据
String sql = "select count(pid) from product";
Long object = qr.query(sql,new ScalarHandler<Long>());
System.out.println(object);
}
/**
* ColumnListHandler : 查询数据表中的一个列的数据,存储到List集合
*/
public static void columnListHandler()throws SQLException{
//创建QueryRunner对象,构造方法,传递DataSource接口实现类
QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
//拼写查询语句
String sql = "select * from product ";
//执行查询语句,传递的对象是ColumnListHandler,要一个列的数据
//ColumnListHandler(String columnName)传递参数,是列名
List<Object> list = qr.query(sql,new ColumnListHandler<Object>("pname"));
for(Object o : list){
System.out.println(o);
}
}
/**
* BeanListHandler : 查询数据表,数据的每一行存储到JavaBean对象,
* 多个JavaBean对象,存储到List集合
* 查询不到数据,集合是存在的,长度=0
*/
public static void beanListHandler()throws SQLException{
//创建QueryRunner对象,构造方法,传递DataSource接口实现类
QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
//拼写查询语句
String sql = "select * from product ";
// 方法query执行SQL语句,传递结果集处理对象 BeanListHandler(传递JavaBean类的class对象)
List<Product> list = qr.query(sql,new BeanListHandler<Product>(Product.class));
for(Product product :list){
System.out.println(product);
}
}
/**
* BeanHandler : 查询数据表的第一行数据,存储到JavaBean对象
* JavaBean对象是 Product
*/
public static void beanHandler()throws SQLException{
//创建QueryRunner类对象,有参数构造方法,传递DataSource接口实现类
QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
//拼写查询语句
String sql = "select * from product ";
//方法query执行SQL语句
//传递结果集BeanHandler(Class<T> type) 传递JavaBean类的class文件对象
Product product = qr.query(sql,new BeanHandler<Product>(Product.class));
System.out.println(product);
}
}