一、什么是连接池:
1. JDBC访问数据库的步骤:
1) 创建连接 --> 2) 访问数据库 --> 3) 关闭连接
2. 使用连接池解决
1) 由服务器在启动的时候,就创建好一定数据的连接对象。
2) 用户从创建好的连接池中,直接取出一个连接对象即可
3) 如果一个连接对象使用完毕,则将连接对象放回到连接池中。
二、数据库连接池API:
1. 数据源接口
javax.sql.DataSource 数据源(连接池),所有的连接池都必须要实现这个接口。
2. 得到连接的方法:
Connection getConnection() 不指定参数,得到一个连接对象
3. 连接池常用的初始参数:(所有的连接池都有默认参数)
1) 初始连接数,连接池创建的时候,创建的连接对象
2) 最大连接数,连接池中连接数上限。
3) 最大等待时间,如果超时,抛出异常。如果连接池中没有连接对象,等待多久。
4) 最大空闲等待时间,如果一个用户得到了连接对象,多久没有发送SQL语句,就会被连接池回收。
(1)自定义连接池
自定义连接池实现的几个步骤:
1. 创建数据库连接类 JdbcUtils 。
2. 创建类MyDataSource类 实现DataSource接口,该类下的步骤主要有:
1) 批量的实现数据库的连接,并把创建的连接放入到LinkList中(因为要进行增和删操作,Linklist比ArrayList性能 高上许多);
2)实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户, 3)在该类中创建方法addBackToPool(Connection con),当用户使用完后,重新将连接 放回到连接池中。
3.编写测试类 进行测试
具体的代码如下:
数据库连接类
—通过读取配置文件properties文件中的配置信息,配置文件就不列举了
package com.mystore.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ResourceBundle;
/**
* 提供数据库连接池 和数据库连接
* 方法为静态的 通过类型访问
* @author huhongda
*
*/
public class JdbcUtils {
private static String driverName = null;
private static String url=null;
private static String userName = null;
private static String userPwd =null;
//读取配置文件中的内容
//静态方法块
static{
ResourceBundle bundle = ResourceBundle.getBundle("dataBase");
driverName = bundle.getString("driverName");
url = bundle.getString("url");
userName= bundle.getString("userName");
userPwd = bundle.getString("userPwd");
}
//建立连接
public static Connection getConnection(){
try {
//注册驱动
loadDriver();
//System.out.println("创建连接成功");
//建立连接 并返回
return DriverManager.getConnection(url, userName, userPwd);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return null;
}
//注册驱动
public static void loadDriver(){
try {
Class.forName(driverName);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
//释放资源
public static void release(ResultSet rs,Statement stat,Connection con){
//存在连接或结果集的时候 释放
if(rs!=null){
try {
rs.close();
} catch (Exception e) {
// TODO: handle exception
}
rs= null;
}
if(stat!=null){
try {
stat.close();
} catch (Exception e) {
// TODO: handle exception
}
stat = null;
}
if(con!=null){
try {
con.close();
} catch (Exception e) {
// TODO: handle exception
}
con = null;
}
}
}
连接池类
package DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;
import javax.sql.DataSource;
import com.mystore.utils.JdbcUtils;
//简单的实现自定义 连接池
public class MyDataSource implements DataSource {
//通过 linkList充当 池
private LinkedList<Connection> pool = new LinkedList<Connection>();
//构造 函数 初始化 连接 数目
public MyDataSource(){
System.out.println("构造函数 创建 20个连接");
for (int i = 0; i < 20; i++) {
//创建 连接
Connection connection = JdbcUtils.getConnection();
//把 创建的连接 放入池子中
pool.add(connection);
}
}
//用完 之后 将传递的连接放回 池中
public void addBackToPool(Connection connection){
pool.add(connection);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
//从线程池 中 取得 第一个
@Override
public Connection getConnection() throws SQLException {
// TODO Auto-generated method stub
//首先 判断 是否为空
if(pool.isEmpty()){
//为空的话 继续创建 5个连接
for (int i = 0; i < 5; i++) {
Connection connection = JdbcUtils.getConnection();
pool.add(connection);
}
}
//有连接的话 就取出第一个
Connection con = pool.removeFirst();
System.out.println("取得一个连接 使用");
return con;
}
@Override
public Connection getConnection(String username, String password)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
}
简单的测试类
package DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.mystore.utils.JdbcUtils;
//对自定义 连接池的 测试
public class TestDataSource {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Connection connection = null;
PreparedStatement stmt = null;
MyDataSource ds = null;
ResultSet rs =null;
try {
ds = new MyDataSource();
//从连接池 中 取得 连接
connection = ds.getConnection();
stmt = connection.prepareStatement("update users set passward ='123' where userName=?");
//给占位符 设值
stmt.setString(1,"huhongda");
//执行
stmt.executeUpdate();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally{
//最终 将 连接 放回到 连接池中
ds.addBackToPool(connection);
System.out.println("使用完 后将连接 放回 连接池中");
//释放 资源 并 不将连接 释放
JdbcUtils.release(rs, stmt, null);
}
}
}
(2)C3P0连接池:
1) 开放源代码,免费使用
2) Hibernate框架(访问数据库)中默认使用的连接池
1. 使用步骤:
1) 导包 c3p0-0.9.5.2.jar 、mchange-commons-java-0.2.12.jar
2) 设置参数(通过源代码或通过配置文件)
要设置两类参数:
2.1) 数据库连接参数(用户名,密码,URL,驱动)
2.2) 数据库连接池的参数
3) 得到连接池(数据源)
4) 从连接池中得到连接对象![]()
1 public static void main(String[] args) throws Exception { 2 // 1.创建数据源对象 3 ComboPooledDataSource ds = new ComboPooledDataSource(); 4 // 2. 设置数据库的连接参数 5 // 用户名,密码,URL,驱动 6 ds.setUser("root"); 7 ds.setPassword("root"); 8 ds.setJdbcUrl("jdbc:mysql://localhost:3306/day25"); 9 ds.setDriverClass("com.mysql.jdbc.Driver"); 10 // 3. 设置连接池的参数 11 ds.setInitialPoolSize(5); // 初始连接数 12 ds.setMaxPoolSize(10); // 最大连接数 13 ds.setCheckoutTimeout(2000); // 最长等待时间,单位:毫秒 14 ds.setMaxIdleTime(1000); // 最长空闲等待时间 15 // 4. 得到连接对象 16 for (int i = 1; i <= 11; i++) { 17 Connection conn = ds.getConnection(); 18 System.out.println("第" + i + "个连接:" + conn); 19 //第5个连接释放 20 if (i ==5) { 21 conn.close(); 22 } 23 } 24 }
使用配置文件配置参数:
1. 使用配置文件的好处:
1) 因为所有的这些配置参数都写在源码中,以后修改不方便。
2) 配置与源码是耦合在一起
2. 配置文件的要求:
1) 文件名:c3p0-config.xml
2) 位置:放在类路径下,放在src目录下
3) 在一个配置文件中,可以有多个配置:
3.1) 默认配置:如果没有指定配置名,则使用默认配置
3.2) 命名配置:如果指定了配置名,则使用指定的配置
3. 多个不同配置的好处:
1) 可以使用不同的连接池的配置参数
2) 可以连接不同的数据库。如:db1, db2
3) 可以使用不同厂商的数据库,如:MySQL,Oracle
2. C3P0连接池的工具类:
1). 创建私有静态数据源成员变量
2). 创建公有的得到数据源的方法
3). 创建得到连接对象的方法

1 /**
2 * 连接池的工具类
3 *
4 * @author NewBoy
5 *
6 */
7 public class C3P0Util {
8 /**
9 * 1. 创建私有静态数据源成员变量
10 */
11 private static ComboPooledDataSource ds = new ComboPooledDataSource();
12
13 /**
14 * 2. 创建公有的得到数据源的方法
15 * @return
16 */
17 public static DataSource getDataSource() {
18 return ds;
19 }
20
21 /**
22 * 3. 创建得到连接对象的方法
23 * @return
24 */
25 public static Connection getConnection() {
26 try {
27 return ds.getConnection();
28 } catch (SQLException e) {
29 e.printStackTrace();
30 }
31 return null;
32 }
33
34 }
(3)DBCP连接池: (DataBase Connection Pool 数据库连接池)
1) 厂商:apache基金组织
2) 开放源代码,免费
3) Tomcat(Web服务器),默认使用的就是DBCP连接池
3. 使用步骤:
1) 下载包
commons-dbcp-1.4.jar 数据库连接池的核心包
commons-pool-1.5.6.jar 辅导支持包
2) 编写代码,创建连接池
public class BasicDataSource implements DataSource
3) 设置参数
3.1) 数据库的连接参数
3.2) 连接池的参数
4) 通过数据源得到连接对象![]()
1 public class Demo1 { 2 3 public static void main(String[] args) throws SQLException { 4 // 1.导包commons-dbcp-1.4.jar 数据库连接池的核心包 commons-pool-1.5.6.jar 辅导支持包 5 // 2) 编写代码,创建连接池 6 BasicDataSource ds = new BasicDataSource(); 7 // 3) 设置参数 8 // 3.1) 数据库的连接参数(用户名,密码,URL,驱动) 9 ds.setUsername("root"); 10 ds.setPassword("root"); 11 ds.setUrl("jdbc:mysql://localhost:3306/day25"); 12 ds.setDriverClassName("com.mysql.jdbc.Driver"); 13 // 3.2) 连接池的参数(初始连接数,最大连接数,最长等待时间,最大等待个数) 14 ds.setInitialSize(5); 15 ds.setMaxActive(10); 16 ds.setMaxWait(2000); 17 ds.setMaxIdle(3); 18 // 4) 通过数据源得到连接对象 19 for (int i = 1; i <=11; i++) { 20 //Cannot get a connection, pool error Timeout waiting for idle object 21 Connection conn = ds.getConnection(); 22 System.out.println("第" + i + "个连接:" + conn.hashCode()); 23 if (i == 5) { 24 conn.close(); //关闭了一个连接 25 } 26 } 27 } 28 }
DBCP使用配置文件加载
1. 配置文件
文件名:xxx.properties
内容:属性名=属性值
1) 属性名:与set方法的名字相同,去掉set,首字母小写,如:setInitialSize 写成 initialSize
2) 位置:建议放在src目录下,使用类加载器得到资源文件![]()
1 # database connection information 2 username=root 3 password=root 4 url=jdbc:mysql://localhost:3306/day25 5 driverClassName=com.mysql.jdbc.Driver 6 # database connect pool information 7 initialSize=5 8 maxActive=10 9 maxWait=2000 10 maxIdle=3
1 代码要点: 2 1) 使用Properties类加载属性文件 3 2) 通过类路径加载输入流 4 3) 通过工厂对象的静态方法,得到DataSource连接池对象 5 4) 通过BasicDataSource类得到连接对象 6 7 代码: 8 public static void main(String[] args) throws Exception { 9 // 1) 使用Properties类加载属性文件 10 Properties info = new Properties(); 11 // 2) 通过类路径加载输入流 12 info.load(Demo2.class.getClassLoader().getResourceAsStream("dbcp.properties")); 13 // 3) 通过工厂对象的静态方法,得到DataSource连接池对象 14 BasicDataSource ds = (BasicDataSource) BasicDataSourceFactory.createDataSource(info); 15 // 4) 通过BasicDataSource类得到连接对象 16 for (int i = 1; i <= 11; i++) { 17 Connection conn = ds.getConnection(); 18 System.out.println(conn.hashCode()); 19 //释放一个 20 if (i==3) { 21 conn.close(); 22 } 23 } 24 }
三.DbUtils工具
1. 组织: apache基金会
2. 特点:
1) 对JDBC进行封装,学习成本低,容易上手。
2) 效率接近于直接使用JDBC的代码
3) 几乎所有增删改查操作,都可以一句话搞定
一、主要类介绍:
1. 导入jar包:commons-dbutils-1.6.jar
2. DbUtils类:
1) 所有的方法都是静态方法
2) 一组释放资源的方法
static void close(Connection conn)
static void close(ResultSet rs)
static void close(Statement stmt)
static void closeQuietly(Connection conn)
static void closeQuietly(Connection conn, Statement stmt, ResultSet rs)
3. QueryRunner类(重点):
进行增删改查的类
4. ResultSetHandler接口:
用于处理查询的结果集,并且对结果集再次进行封装。
ResultSet -> List<Student>
二. QueryRunner类的主要方法
1. 方式一:
1) 传入数据源的构造方法:
QueryRunner(DataSource ds)
2) 增删改的方法
int update(String sql) SQL语句
int update(String sql, Object... params) SQL语句中有多个占位符,参数用来替换占位符的真实的值
int update(String sql, Object param) SQL语句中只有一个占位符,参数用来替换占位符的真实的值
返回影响的行数
3) 无需关闭连接
因为update方法的内部已经关闭了连接对象

1 public class Demo1 {
2 // 1.创建QueryRunner类,在构造方法中传入了数据源
3 QueryRunner runner = new QueryRunner(C3P0Util.getDataSource());
4
5 @Test
6 public void testAdd() throws SQLException {
7 // 2. 向数据库中添加一条记录
8 runner.update("insert into student (name,gender,birthday) values (?,?,?)", "唐僧", "男",
9 java.sql.Date.valueOf("2000-11-11"));
10 }
11
12 @Test
13 public void testUpdate() throws SQLException {
14 //将id为2的学生,性别改成女
15 runner.update("update student set gender=? where id=?", "女", 2);
16 }
17
18 @Test
19 public void testDelete() throws SQLException {
20 //删除姓名为:龟仙人记录
21 runner.update("delete from student where name=?", "龟仙人");
22 }
23 }
2. 方式二:
1) 无参的构造方法:new QueryRunner()
2) 增删改的方法
传入了连接对象
int update(Connection conn, String sql) 只有SQL语句
int update(Connection conn, String sql, Object... params) 多个参数,有多个占位符
int update(Connection conn, String sql, Object param) 一个参数,一个占位符
3) 关闭连接
需求自己手动关闭连接

1 // 创建QueryRunner类
2 QueryRunner runner = new QueryRunner();
3
4 @Test
5 public void testAdd() throws SQLException {
6 // 得到连接对象
7 Connection conn = C3P0Util.getConnection();
8 // 添加1条记录
9 int row = runner.update(conn, "insert into student(name,gender,birthday) values (?,?,?)", "小乔", "女",
10 java.sql.Date.valueOf("2000-03-20"));
11 //连接对象需要自己关闭
12 DbUtils.close(conn);
13 System.out.println(row);
14 }
3. 查询有关的方法(需要时实现ResultSetHandler接口)
1) 没有连接对象的
<T> T query(String sql, ResultSetHandler<T> rsh)
传入SQL语句和结果集的处理类
<T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
sql: SQL语句
rsh:结果集处理类
params:替换占位符的参数
2) 有连接对象的
<T> T query(Connection conn, String sql, ResultSetHandler<T> rsh)
<T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params)
三. ResultSetHandler接口
1. 方法:
T handle(ResultSet rs) 将结果集转成一个对象

1 实现类:
2 示例:查询学生信息表中1条记录
3
4 public class Demo3 {
5 //创建QueryRunner对象
6 QueryRunner runner = new QueryRunner(C3P0Util.getDataSource());
7
8 @Test
9 public void testQueryStudent() throws SQLException{
10 //通过id查询一个学生
11 Student student = runner.query("select * from student where id=?", new StudentHandler(), 3);
12 System.out.println(student);
13 }
14 }
15
16 public class StudentHandler implements ResultSetHandler<Student> {
17 @Override
18 public Student handle(ResultSet rs) throws SQLException {
19 //如果有结果集
20 Student student = new Student();
21 if (rs.next()) {
22 student.setId(rs.getInt("id"));
23 student.setName(rs.getString("name"));
24 student.setGender(rs.getString("gender"));
25 student.setBirthday(rs.getDate("birthday"));
26 }
27 return student;
28 }
29 }
2. 常用的实现类(已经实现了ResultSetHandler接口):
1) 封装成JavaBean:查询一条记录的时候
前提:表的列名与类的属性名相同
BeanHandler<>();
2) 封装成List<JavaBean>
BeanListHandler<>();
查询多条记录的时候
3) 单行单列:用于聚合函数查询
ScalarHandler<>();