首页 > 代码库 > JDBC-数据连接池的使用

JDBC-数据连接池的使用

数据库连接池(connection pool) 

   在昨天的练习中每一次练习都需要与数据库建立连接,完成时断开连接,然而当处理的数据量特别的时候,就很耗费时间、降低效率,今天我们学习使用连接池,将连接放在连接池中,需要使用的时候从中取出,使用完毕放回池中并不是断开连接。

   数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
   数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
   为解决传统开发中的数据库连接问题,可以采用数据库连接池技术。
   数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。

DBCP连接池

     首先我们使用DBCP连接池(一个免费开源的连接池),我们需要先将commons-dbcp-1.4.jar文件放置当前工程下,并配置环境(添加到Build Path)。下面通过一个程序了解如何使用DBCP连接池:

    我们在这里和之前一样需要创建一个“dbcp.properties”文件,将必要的参数放入其中,其内容如下,(此文件放在当前工程下),DBCP连接池使用这个文件可以完成mysql、oracle的连接池的建立,但是每次只能建立一个,另一个需要注释起来。

driverClassName = com.mysql.jdbc.Driver

url = jdbc:mysql://127.0.0.1:3306/company

username = root

password = 123456


initialSize = 5

maxActive = 50

maxIdle = 10


#driverClassName = oracle.jdbc.driver.OracleDriver

#url = jdbc:oracle:thin:@127.0.0.1:1521:orcl

#username = scott

#password = tiger

package com.atguigu.jdbc;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;

public class DBCPTest {
	@Test
	public void test2() throws Exception {
		Properties properties = new Properties();
		properties.load(new FileInputStream("dbcp.properties"));
		DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
		System.out.println("inital:" + ((BasicDataSource)dataSource).getInitialSize());
		System.out.println("getMaxActive:" + ((BasicDataSource)dataSource).getMaxActive());
		System.out.println("getMaxIdle:" + ((BasicDataSource)dataSource).getMaxIdle());
		Connection connection = dataSource.getConnection();
		System.out.println(connection);
		connection.close();
	}
}

C3P0连接池

     下面我们学习一个功能更加强大的连接池,C3P0(仍然是一个免费开源的连接池),如上我们需要先将commons-dbcp-1.4.jar文件放置当前工程下,并配置环境(添加到Build Path)。
这里通过一个程序了解如何使用DBCP连接池:
如同DBCP连接池,我们需要创建一个“c3p0-config.xml”文件,将必要的参数放入其中,其内容如下,(此文件放在当工程的src目录)

<c3p0-config> 
<named-config name="mysql-config"> 
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/school</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquireIncrement">5</property> 
<property name="initialPoolSize">5</property> 
<property name="minPoolSize">5</property> 
<property name="maxPoolSize">50</property> 
<property name="maxStatements">0</property> 
<property name="maxStatementsPerConnection">5</property> 
</named-config> 
<named-config name="orcale-config">
<property name="driverClass">oracle.jdbc.driver.OracleDriver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/school</property>
<property name="user">root</property>
<property name="password">123456</property>
</named-config>
</c3p0-config>

       DBCP连接池使用这个文件可以完成mysql、oracle的连接池的建立,每次只能建立一个,但是另一个需要注释起来。因为我们是根据<named-config name="mysql-config"> 名建立连接,

package com.atguigu.jdbc;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.Test;

import com.mchange.v2.c3p0.*;

public class C3P0Test {
	@Test
	public void test1() throws PropertyVetoException, SQLException {
		DataSource dataSource = new ComboPooledDataSource("mysql-config"); // 它会默认自动去读取文件
		System.out.println(dataSource);
		Connection connection = dataSource.getConnection();
		System.out.println(connection);
		connection.close();// 把连接归还给连接池
		
		DataSources.destroy(dataSource);// 完全释放池中所有连接,并销毁连接池!!
	}		
		
	@Test
	public void test2() throws PropertyVetoException, SQLException {
		DataSource dataSource = new ComboPooledDataSource("oracle-config"); // 它会默认自动去读取文件
		System.out.println(dataSource);
		Connection connection = dataSource.getConnection();
		System.out.println(connection);
		connection.close();// 把连接归还给连接池
		
		DataSources.destroy(dataSource);// 完全释放池中所有连接,并销毁连接池!!
	}	
}

 学习了连接池之后,JdbcUtil工具类中的getConnection方法就可以应用,如下:

package com.atguigu.jdbc;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;

/**
 * 预备工作 : 
 * 	1) 把要访问的数据库相关的驱动程序复制到项目中, 就是jar包
 * 	2) 配置项目属性, 把jar包导入到本项目的buildpath中
 * @author Administrator
 *
 */
public class JdbcUtil {
	
	private static DataSource dataSource; // 声明静态属性对象引用.
	
	static {
		dataSource = new ComboPooledDataSource("mysql-config"); // 连接池对象只需要创建一次就可以了
	}
	
	public static Connection getConnection() throws SQLException {
		return dataSource.getConnection(); // 要想获取连接, 只需要从连接池中获取,用完以后, 再归还回来
	}
	
	public static Connection getConnectionOld() throws IOException, ClassNotFoundException, SQLException {
		// 1) 读取配置文件
		Properties properties = new Properties();
		properties.load(new FileInputStream("jdbc.properties"));
		// 2) 获取配置文件中的必要的信息
		String driverClass = properties.getProperty("driverClass");
		String url = properties.getProperty("url");
		String user = properties.getProperty("user");
		String password = properties.getProperty("password");
		// 3) 注册驱动 , 加载驱动类
		Class.forName(driverClass);
		// 4) 通过驱动管理器获取连接(需要url,用户,密码)
		return DriverManager.getConnection(url, user, password);// 暗含  new Socket(host,port), 认证,其他各种初始化操作
	}
	
	//关闭连接
	public static void close(Connection connection) {
		close(connection, null);
	}
	
	public static void close(Connection connection, Statement statement) {
		close(connection, statement, null);
	}
	
	public static void close(Connection connection, Statement statement, ResultSet resultSet) {
		if (resultSet != null) {
			try {
				resultSet.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		if (statement != null) {
			try {
				statement.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		if (connection != null) {
			try {
				connection.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	//销毁连接池
	public static void destroy() {
		try {
			DataSources.destroy(dataSource);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}	
}

DBUtils工具类

将常用的操作数据库的JDBC的类和方法集合在一起,就是DBUtils.JDBC。提供供我们使用的工具类QueryRunner来执行操作。
在使用之前我们仍然需要将commons-dbutils-1.3.jar添加到当前工程下,并添加到path路径。
package com.atguigu.jdbc;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;

public class QueryRunnerTest {

	// 使用我们自定义工具实现表的创建
	@Test
	public void test1() throws SQLException {
		QueryRunner qr = new QueryRunner();
		Connection connection = JdbcUtil.getConnection();
		qr.update(connection, "create table test2(aa int, bb varchar(10))");
		JdbcUtil.close(connection);
	}	
	
	// 使用我们自定义工具向表中插入一条记录
	@Test
	public void test2() throws SQLException {
		QueryRunner qr = new QueryRunner();
		Connection connection = JdbcUtil.getConnection();
		int rows = qr.update(connection, "insert into test2(aa, bb) values(?,?)", 10, "xxx");
		System.out.println(rows + " rows");
		JdbcUtil.close(connection);
	}
	
	// 使用DBUtils.JDBC接口中提供的方法对departments表进行查询,把结果集中的所有记录转换为department对象集合并存入List集合中,然后遍历输出对象
	@Test
	public void test3() throws SQLException {
		//query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) 
		String sql = "select * from departments where department_id > ?";
		QueryRunner qr = new QueryRunner();
		Connection connection = JdbcUtil.getConnection();
		BeanListHandler<Department> rsh = new BeanListHandler<Department>(Department.class); // 把结果集中的所有记录转换为对象集合
		List<Department> list = qr.query(connection, sql, rsh, 20);
		for (Department department : list) {
			System.out.println(department);
		}
	}	
	
	// 使用DBUtils.JDBC接口中提供的方法对departments表进行查询,把结果集中的一条记录转换为department实体对象,然后输出对象
	@Test
	public void test4() throws SQLException {
		String sql = "select * from departments where department_id = ?";
		QueryRunner qr = new QueryRunner();
		Connection connection = JdbcUtil.getConnection();
		BeanHandler<Department> rsh = new BeanHandler<Department>(Department.class); // 把结果集中的一条记录转换为实体对象
		Department objDepartment = qr.query(connection, sql, rsh, 20);
		System.out.println(objDepartment);
	}
	
	// 使用DBUtils.JDBC接口中提供的方法对departments表进行查询,将每一条记录存入集合中,然后遍历输出每一个数据
	@Test
	public void test5() throws SQLException {
		String sql = "select * from employees";
		QueryRunner qr = new QueryRunner();
		Connection connection = JdbcUtil.getConnection();
		ArrayListHandler rsh = new ArrayListHandler();
		List<Object[]> list = qr.query(connection, sql, rsh);
		for (Object[] objects : list) {
			for (int i = 0; i < objects.length; i++) {
				System.out.print(objects[i] + "\t");
			}
			System.out.println();
		}
	}		
		
	// 使用DBUtils.JDBC接口中提供的方法对departments表进行查询,将查询到的一个数据输出	
	@Test
	public void test6 () throws SQLException {
		String sql = "select count(*) from world.country";
		QueryRunner qr = new QueryRunner();
		Connection connection = JdbcUtil.getConnection();
		ScalarHandler rsh = new ScalarHandler();
		Object singleValue = http://www.mamicode.com/qr.query(connection, sql, rsh);>到这里就可以统一整理一下自己定义的JdbcUtil工具类、CommonUtil工具类,使自定义的工具类能达到JDButi.JDBC相同的功能,如下:
JdbcUtils.java

package com.atguigu.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;

public class JdbcUtil {
	
	private static DataSource dataSource;
	
	static {
		dataSource = new ComboPooledDataSource("config1"); // 它必须依赖文件src/c3p0-config.xml
	}
	
	// 获取c3p0连接池的连接
	public static Connection getConnection() throws SQLException {
		return dataSource.getConnection();
	}
	
	public static void close(Connection connection) {
		close(connection, null);
	}
	
	public static void close(Connection connection, Statement statement) {
		close(connection, statement, null);
	}
	
	public static void close(Connection connection, Statement statement, ResultSet resultSet) {
		if (resultSet != null) {
			try {
				resultSet.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		if (statement != null) {
			try {
				statement.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		if (connection != null) {
			try {
				connection.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void destroy() {
		try {
			DataSources.destroy(dataSource);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

CommonUtil.java

package com.atguigu.jdbc;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class CommonUtil {
	
	/**
	 * 把结果集中的每一行都放入Object对象数组中, 再把所有的Object对象数组放入一个List集合中.
	 * @throws SQLException 
	 */
	public static List<Object[]> query(Connection connection, String sql, Object... values) throws SQLException {
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		try {
			preparedStatement = connection.prepareStatement(sql);
			fillArguments(preparedStatement, values);
			resultSet = preparedStatement.executeQuery();
			List<Object[]> list = new ArrayList<Object[]>();
			int cols = resultSet.getMetaData().getColumnCount();
			while (resultSet.next()) {
				Object[] dataRow = new Object[cols];
				for (int i = 0; i < dataRow.length; i++) {
					dataRow[i] = resultSet.getObject(i + 1);
				}
				list.add(dataRow);
			}
			return list;
		} finally {
			JdbcUtil.close(null, preparedStatement, resultSet);
		}
	}

	/**
	 * 把结果集中的第一行数据,全放入一个对象数组中
	 * @throws SQLException 
	 */
	public static Object[] queryValueArray(Connection connection, String sql, Object... values) throws SQLException {
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		try {
			preparedStatement = connection.prepareStatement(sql);
			fillArguments(preparedStatement, values);
			resultSet = preparedStatement.executeQuery();
			if (resultSet.next()) {
				Object[] dataRow = new Object[resultSet.getMetaData().getColumnCount()];
				for (int i = 0; i < dataRow.length; i++) {
					dataRow[i] = resultSet.getObject(i + 1);
				}
				return dataRow;
			} else {
				return null;
			}
		} finally {
			JdbcUtil.close(null, preparedStatement, resultSet);
		}
	}
	
	/**
	 * 从结果集中获取第一行的第一列
	 * @throws SQLException 
	 */
	public static Object queryValue(Connection connection, String sql, Object... values) throws SQLException {
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		try {
			preparedStatement = connection.prepareStatement(sql);
			fillArguments(preparedStatement, values);
			resultSet = preparedStatement.executeQuery();
			if (resultSet.next()) {
				return resultSet.getObject(1);
			} else {
				return null;
			}
		} finally {
			JdbcUtil.close(null, preparedStatement, resultSet);
		}
	}
	
	/**
	 * 把结果集中第一行转换为对象返回
	 * @throws SQLException 
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 */
	public static <T> T queryBean(Connection connection, String sql, Class<T> clazz, Object... values) throws SQLException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		try {
			preparedStatement = connection.prepareStatement(sql);
			
			fillArguments(preparedStatement, values);
			
			resultSet = preparedStatement.executeQuery();
			if (resultSet.next()) {
				T t = clazz.newInstance();
				ResultSetMetaData metaData = http://www.mamicode.com/resultSet.getMetaData();>

BaseDAO

综合之前学习过的知识,在这里创建一个BaseDAO<T>类借助DBUtils工具类实现数据操作功能:

package com.atguigu.jdbc;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
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.apache.commons.dbutils.handlers.ScalarHandler;

public class BaseDAO<T>{

	protected Class<T> clazz; // T泛型究竟是什么类型, 用类模板对象来描述
	protected QueryRunner qr = new QueryRunner(); // 用于执行通用查询和更新的工具类对象
	protected Connection connection; // 数据库连接
	protected String tableName; // 涉及到的表,需要通过构造器初始化赋值
	
	public JdbcDAO(String tableName) {
		// 以下代码的执行者是子类对象,所以this.getClass是获取子类的类模板对象
		Type type = this.getClass().getGenericSuperclass(); // JdbcDAO<Teacher>
		if (type instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType)type;//JdbcDAO<Teacher>
			Type[] types = parameterizedType.getActualTypeArguments();
			clazz = (Class<T>)types[0];
		} else {
			clazz = (Class<T>)Object.class;
		}
		// 获取一个连接供所有方法使用
		try {
			connection = JdbcUtil.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		this.tableName = tableName;
	}
	
	//获得记录中具体的一个数据
	public Object getValue(String sql, Object... values) {
		try {
			return qr.query(connection, sql, new ScalarHandler(), values);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	//获得一行数据并封装成javabean对象
	public T get(String sql, Object... values) {
		try {
			return qr.query(connection, sql, new BeanHandler<T>(clazz), values);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	//获得多行记录,封装成javabean对象,保存在list集合中
	public List<T> getList(String sql, Object... values) {
		try {
			return qr.query(connection, sql, new BeanListHandler<T>(clazz), values);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	
	//获得所有记录,封装成javabean对象,保存在list集合中
	public List<T> getAll() {
		return getList("select * from " + tableName);
	}
	
	//根据id获取某一条记录,并封装成javabean对象返回
	public T getById(int id) {
		return get("select * from " + tableName + " where id = ?", id);
	}
	
	//根据id删除某一条记录,删除成功返回ture,失败返回false
	public boolean deleteById(int id) {
		int rows = update("delete from " + tableName + " where id = ?", id);
		if (rows > 0) {
			return true;
		}
		return false;
	}

	//通用的更新操作
	public int update(String sql, Object... values) {
		try {
			return qr.update(connection, sql, values);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return 0;
	}
	
	//关闭连接
	public void close() {
		JdbcUtil.close(connection);
	}
}







    

JDBC-数据连接池的使用