连接池:
一、什么是连接池:
1. JDBC访问数据库的步骤:
1) 创建连接 --> 2) 访问数据库 --> 3) 关闭连接
2. 使用连接池解决
1) 由服务器在启动的时候,就创建好一定数据的连接对象。
2) 用户从创建好的连接池中,直接取出一个连接对象即可
3) 如果一个连接对象使用完毕,则将连接对象放回到连接池中。
二、数据库连接池API:
1. 数据源接口
javax.sql.DataSource 数据源(连接池),所有的连接池都必须要实现这个接口。
2. 得到连接的方法:
Connection getConnection() 不指定参数,得到一个连接对象
3. 连接池常用的初始参数:(所有的连接池都有默认参数)
1) 初始连接数,连接池创建的时候,创建的连接对象
2) 最大连接数,连接池中连接数上限。
3) 最大等待时间,如果超时,抛出异常。如果连接池中没有连接对象,等待多久。
4) 最大空闲等待时间,如果一个用户得到了连接对象,多久没有发送SQL语句,就会被连接池回收。
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) 从连接池中得到连接对象
c3po连接池使用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 }
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) 通过数据源得到连接对象
dbcp示例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目录下,使用类加载器得到资源文件
dbcp配置文件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
dbcp示例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<>();

1 public class Demo3 { 2 3 // 创建QueryRunner对象 4 QueryRunner runner = new QueryRunner(C3P0Util.getDataSource()); 5 6 @Test 7 public void testQueryStudent() throws SQLException { 8 // 通过id查询一个学生 9 Student student = runner.query("select * from student where id=?", new StudentHandler(), 3); 10 System.out.println(student); 11 } 12 13 @Test 14 public void testQueryStudent2() { 15 // 通过id查询一个学生 16 try { 17 Student student = runner.query("select * from student where id=?", new BeanHandler<Student>(Student.class), 18 2); 19 System.out.println(student); 20 } catch (SQLException e) { 21 e.printStackTrace(); 22 } 23 } 24 25 // 查询多个学生 26 @Test 27 public void testQueryStudents() { 28 try { 29 List<Student> students = runner.query("select * from student", new BeanListHandler<Student>(Student.class)); 30 for (Student student : students) { 31 System.out.println(student); 32 } 33 } catch (SQLException e) { 34 e.printStackTrace(); 35 } 36 } 37 38 // 查询聚合函数: 查询女生的个数 39 @Test 40 public void testQueryGender() { 41 //java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer 42 try { 43 long num = runner.query("select count(*) from student where gender=?", new ScalarHandler<Long>(), "女"); 44 System.out.println(num); 45 } catch (SQLException e) { 46 e.printStackTrace(); 47 } 48 } 49 }