C3P0
是一个开源的
JDBC
连接池
,它实现了数据源和
JNDI
绑定,支持
JDBC3
规范和
JDBC2
的标准扩展。目前使用它的
开源项目
有
Hibernate,Spring
等。
c3p0 - JDBC3.jar下载地址:http://www.java2s.com/Code/Jar/c/Downloadc3p00912jar.htm
commons-dbutils-1.7.jar下载地址:http://commons.apache.org/proper/commons-dbutils/download_dbutils.cgi
使用步骤:
1、将下载的c3p0-0.9.5.2.jar和commons-dbutils-1.7.jar及数据库驱动程序导入项目中

2、在scr下新建xml文件取名为c3p0-config.xml 并配置内容如下:
<?
xml version="1.0" encoding="UTF-8"
?>
<c3p0-config> <default-config> <!--mysql数据库连接的各项参数--> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb?characterEncoding=utf-8</property> <property name="user">root</property> <property name="password">root</property> <!--配置数据库连接池的最小链接数、最大连接数、初始连接数--> <property name="maxPoolSize">15</property> <property name="minPoolSize">5</property> <property name="initialSize">5</property> </default-config> </c3p0-config>
3、在项目新建一个BaseUtils工具类类
/**
* @描述: 工具类 提供数据库连接对象
* @作者:刘运发
* @创建时间:2018年4月3日 上午8:45:15
* @版本:V1.0
*/
public class BaseUtil {
private static DataSource dataSource = null;
static {
// 自动加载src目录下面的c3p0的配置文件,【c3p0-config.xml】
dataSource = new ComboPooledDataSource();
}
public static QueryRunner getQueryRunner() {
// 第一步:创建QueryRunner对象,传入连接池对象
// 在创建QueryRunner对象的时候,如果传入数据对象dataSource,
// 那么在使用QueryRunner对象的方法时候,就不需要传入连接对象
QueryRunner query = new QueryRunner(dataSource);
// 第二步:会自动从数据源中获取连接(不用关闭连接,连接池会自动关闭连接对象)
return query;
}
/***
* 实现增删改的公共方法
*
* @param sql
* @param arr
* @return
*/
public static boolean addUpdateDelete(String sql, Object[] arr) {
QueryRunner qr = getQueryRunner();
int count;
try {
count = qr.update(sql, arr);
if (count > 0) {
return true;
} else {
return false;
}
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
}
4、创建好实体类
package org.bdqn.entity;
public class User {
private int id;
private String name;
private String password;
private String email;
private String phone;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
/**
* 重写toString方法 输出实体类的详细信息
*/
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password
+ ", email=" + email + ", phone=" + phone + "]";
}
}
5、dao层进行创建接口,再创建实现接口的类,当然实现c3p0和QueryRunner的关键代码就是dao层
package org.bdqn.dao;
import java.util.List;
import org.bdqn.entity.User;
public interface UserDao {
/***
* 查询所有用户信息
* @param user
* @return
*/
public List<User> selectUser();
/***
* 根据条件查询用户信息
* @param user
* @return
*/
public List<User> select(User user);
/***
* 添加用户信息
* @param user
* @return
*/
public boolean insertUser(User user);
/***
* 修改用户的信息
* @param user
* @return
*/
public boolean updateUser(User user);
/***
* 删除用户信息
* @param id
* @return
*/
public boolean deleteUser(int id);
}
6、创建接口实现类去实现UserDao
package org.bdqn.dao.impl;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.bdqn.dao.UserDao;
import org.bdqn.entity.User;
import org.bdqn.util.BaseUtil;
public class UserDaoImpl implements UserDao {
public List<User> selectUser() {
// 创建QueryRunner
// 记住查询是BeanListHandler BeanHandler
QueryRunner qr = BaseUtil.getQueryRunner();
try {
String sql = "select * from user ";
// 创建BeanListHandler对象
return qr.query(sql, new BeanListHandler<User>(User.class));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public List<User> select(User user) {
QueryRunner qr = BaseUtil.getQueryRunner();
String sql = "select * from user where name =? ";
try {
return qr.query(sql, new BeanListHandler<User>(User.class),
user.getName());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
// 增删改 是使用 BeanListHandler
@Override
public boolean insertUser(User user) {
// 注意主键ID是否有自增 注意数据库的类型 改写sql语句
String sql = "insert into user values(?,?,?,?,?)";
Object[] param = { user.getId(), user.getName(), user.getPassword(),
user.getEmail(), user.getPhone() };
return BaseUtil.addUpdateDelete(sql, param);
}
@Override
public boolean updateUser(User user) {
String sql = "update user set name=? ,password=?,email=?,phone=? where id=?";
Object[] param = { user.getName(), user.getPassword(), user.getEmail(),
user.getPhone() ,user.getId() };
return BaseUtil.addUpdateDelete(sql, param);
}
@Override
public boolean deleteUser(int id) {
String sql = "delete from user where id=" + id;
// 如果不需要传递参数 直接写null
return BaseUtil.addUpdateDelete(sql, null);
}
}
7、测试
public class QueryRunnerTest {
private UserDao dao=new UserDaoImpl();
private UserService service=new UserServiceImpl();
//查询所有信息的测试
@Test
public void selectUser(){
List<User> list=dao.selectUser();
for(User u:list){
System.out.println(u);
}
}
//根绝id查询的信息
@Test
public void selectUserId(){
User user=dao.selectUserId(1);
System.out.println(user);
}
//根据条件查询信息
@Test
public void select(){
User user=new User();
user.setName("张三");
List<User> list=service.select(user);
for(User u:list){
System.out.println(u);
}
}
@Test
public void insertUser(){
User user=new User();
user.setName("张三");
user.setPassword("123456");
user.setEmail("1748@qq.com");
user.setPhone("11223");
boolean mark=service.insertUser(user);
if(mark){
System.out.println("插入成功");
}else{
System.out.println("插入失败");
}
}
@Test
public void update(){
User user=new User();
user.setName("李四");
user.setId(1);
boolean mark=service.updateUser(user);
if(mark){
System.out.println("修改成功");
}else{
System.out.println("修改失败");
}
}
@Test
public void delete(){
boolean mark=service.deleteUser(1);
if(mark){
System.out.println("用户信息删除成功");
}else{
System.out.println("用户信息删除失败");
}
}
}
附录:QueryRunner其他方法:
1、 QueryRunner数据查询操作,结果集八种处理方法
QueryRunner数据查询操作
调用QueryRunner类方法
query(Connection con,String sql,ResultSetHandler r,Object..params)
conn: 连接对象,如果在创建QueryRunner对象时给过dataSource对象则可以忽略
ResultSetHandler r :结果集的封装处理方式,传递ResultSetHandler接口实现类
Object...params : sql语句的?占位符 可以是数组 也可以是一个或多个 Object 值 如果不需要传参 赋值null
注意:query方法返回值,返回的是T 泛型,具体返回值类型,跟随结果集处理方式变化
public class QueryRunnerDemo1 {
/*
* 结果集第八种处理方法,MapListHandler
* 将结果集每一行存储到Map集合,键:列名,值:数据
* Map集合过多,存储到List集合
*/
public static void mapListHandler()throws SQLException{
QueryRunner qr = BaseUtil.getQueryRunner();
String sql = "SELECT * FROM user";
//调用方法query,传递结果集实现类MapListHandler
//返回值List集合, 存储的是Map集合
List<Map<String,Object>> list = qr.query(sql, new MapListHandler());
//遍历集合list
for( Map<String,Object> map : list ){
for(String key : map.keySet()){
System.out.print(key+"..."+map.get(key));
}
System.out.println();
}
}
/*
* 结果集第七种处理方法,MapHandler
* 将结果集第一行数据,封装到Map集合中
* Map<键,值> 键:列名 值:这列的数据
*/
public static void mapHandler()throws SQLException{
QueryRunner qr = BaseUtil.getQueryRunner();
String sql = "SELECT * FROM user";
//调用方法query,传递结果集实现类MapHandler
//返回值: Map集合,Map接口实现类, 泛型
Map<String,Object> map = qr.query( sql, new MapHandler());
//遍历Map集合
for(String key : map.keySet()){
System.out.println(key+".."+map.get(key));
}
}
/*
* 结果集第六种处理方法,ScalarHandler
* 对于查询后,只有1个结果
*/
public static void scalarHandler()throws SQLException{
QueryRunner qr =BaseUtil.getQueryRunner();
String sql = "SELECT COUNT(*) FROM user";
//调用方法query,传递结果集处理实现类ScalarHandler
long count = qr.query( sql, new ScalarHandler<Long>());
System.out.println(count);
}
/*
* 结果集第五种处理方法,ColumnListHandler
* 结果集,指定列的数据,存储到List集合
* List<Object> 每个列数据类型不同
*/
public static void columnListHandler()throws SQLException{
QueryRunner qr = BaseUtil.getQueryRunner();
String sql = "SELECT * FROM user";
//调用方法 query,传递结果集实现类ColumnListHandler
//实现类构造方法中,使用字符串的列名
List<Object> list = qr.query(sql, new ColumnListHandler<Object>("name"));
for(Object obj : list){
System.out.println(obj);
}
}
/*
* 结果集第四种处理方法, BeanListHandler
* 结果集每一行数据,封装JavaBean对象
* 多个JavaBean对象,存储到List集合
*/
public static void beanListHander()throws SQLException{
QueryRunner qr = BaseUtil.getQueryRunner();
String sql = "SELECT * FROM user";
//调用方法query,传递结果集处理实现类BeanListHandler
List<User> list = qr.query( sql, new BeanListHandler<User>(User.class));
for(User s : list){
System.out.println(s);
}
}
/*
* 结果集第三种处理方法,BeanHandler
* 将结果集的第一行数据,封装成JavaBean对象
* 注意: 被封装成数据到JavaBean对象, User类必须有空参数构造
*/
public static void beanHandler()throws SQLException{
QueryRunner qr =BaseUtil.getQueryRunner();
String sql = "SELECT * FROM user";
//调用方法,传递结果集实现类BeanHandler
//BeanHandler(Class<T> type)
User user = qr.query( sql, new BeanHandler<User>(User.class));
System.out.println(user);
}
/*
* 结果集第二种处理方法,ArrayListHandler
* 将结果集的每一行,封装到对象数组中, 出现很多对象数组
* 对象数组存储到List集合
*/
public static void arrayListHandler()throws SQLException{
QueryRunner qr = BaseUtil.getQueryRunner();
String sql = "SELECT * FROM user";
//调用query方法,结果集处理的参数上,传递实现类ArrayListHandler
//方法返回值 每行是一个对象数组,存储到List
List<Object[]> result= qr.query( sql, new ArrayListHandler());
//集合的遍历
for( Object[] objs : result){
//遍历对象数组
for(Object obj : objs){
System.out.print(obj+" ");
}
System.out.println();
}
}
/*
* 结果集第一种处理方法, ArrayHandler
* 将结果集的第一行存储到对象数组中 Object[]
*/
public static void arrayHandler()throws SQLException{
QueryRunner qr = BaseUtil.getQueryRunner();
String sql = "SELECT * FROM user";
//调用方法query执行查询,传递连接对象,SQL语句,结果集处理方式的实现类
//返回对象数组
Object[] result = qr.query( sql, new ArrayHandler());
for(Object obj : result){
System.out.print(obj);
}
}
}
附录2:c3p0-config.xml模板详解(了解)
<
c3p0-config
>
<default-config> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --> <property name="acquireIncrement">3</property> <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 --> <property name="acquireRetryAttempts">30</property> <!--两次连接中间隔时间,单位毫秒。Default: 1000 --> <property name="acquireRetryDelay">1000</property> <!--连接关闭时默认将所有未提交的操作回滚。Default: false --> <property name="autoCommitOnClose">false</property> <!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么 属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试 使用。Default: null--> <property name="automaticTestTable">Test</property> <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试 获取连接失败后该数据源将申明已断开并永久关闭。Default: false--> <property name="breakAfterAcquireFailure">false</property> <!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出 SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --> <property name="checkoutTimeout">100</property> <!--通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。 Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester--> <property name="connectionTesterClassName"></property> <!--指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可 Default: null--> <property name="factoryClassLocation">null</property> <!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs. (文档原文)作者强烈建议不使用的一个属性--> <property name="forceIgnoreUnresolvedTransactions">false</property> <!--每60秒检查所有连接池中的空闲连接。Default: 0 --> <property name="idleConnectionTestPeriod">60</property> <!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 --> <property name="initialPoolSize">3</property> <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --> <property name="maxIdleTime">60</property> <!--连接池中保留的最大连接数。Default: 15 --> <property name="maxPoolSize">15</property> <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0--> <property name="maxStatements">100</property> <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 --> <property name="maxStatementsPerConnection"></property> <!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能 通过多线程实现多个操作同时被执行。Default: 3--> <property name="numHelperThreads">3</property> <!--当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0 的数据源时。Default: null--> <property name="overrideDefaultUser">root</property> <!--与overrideDefaultUser参数对应使用的一个参数。Default: null--> <property name="overrideDefaultPassword">password</property> <!--密码。Default: null--> <property name="password"></property> <!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意: 测试的表必须在初始数据源的时候就存在。Default: null--> <property name="preferredTestQuery">select id from test where id=1</property> <!--用户修改系统配置参数执行前最多等待300秒。Default: 300 --> <property name="propertyCycle">300</property> <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable 等方法来提升连接测试的性能。Default: false --> <property name="testConnectionOnCheckout">false</property> <!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false --> <property name="testConnectionOnCheckin">true</property> <!--用户名。Default: null--> <property name="user">root</property> <!--早期的c3p0版本对JDBC接口采用动态反射代理。在早期版本用途广泛的情况下这个参数 允许用户恢复到动态反射代理以解决不稳定的故障。最新的非反射代理更快并且已经开始 广泛的被使用,所以这个参数未必有用。现在原先的动态反射与新的非反射代理同时受到 支持,但今后可能的版本可能不支持动态反射代理。Default: false--> <property name="usesTraditionalReflectiveProxies">false</property> <property name="automaticTestTable">con_test</property> <property name="checkoutTimeout">30000</property> <property name="idleConnectionTestPeriod">30</property> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <property name="maxPoolSize">25</property> <property name="minPoolSize">10</property> <property name="maxStatements">0</property> <user-overrides user="swaldman"> </user-overrides> </default-config> <named-config name="dumbTestConfig"> <property name="maxStatements">200</property> <user-overrides user="poop"> <property name="maxStatements">300</property> </user-overrides> </named-config> </c3p0-config>