基本概念
先看一张普通连接数据库图:
多个用户操作数据库,向数据库获得链接。数据库创建连接需要较大的资源,而且创建时间长,假设一个网站一天有超10万的访问量,则数据库就需要创建更多的连接,这样极大的浪费资源,而且很容易造成数据库服务器内存溢出、拓机。
如何解决此类问题,出现了数据库连接池。如图所示:
连接池相当于一个容器(集合),存放数据库连接的容器。当系统初始化好了以后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,当用户访问完,会将连接对象归还给容器。
详细点就是:
使用连接对象之前先创建好规定数量(根据服务器内存的承载能力制定)的连接对象存到放连接池(实现池子的方式一般是用链表结构的集合来实现)中,当应用服务器需要连接对象的时候就从连接池中获取,用完该连接对象时归还连接对象到连接池中。当应用服务器需要连接对象而当前池子中没有连接对象可取时,就让其先等待,如果等待超时还没有回获取到连接对象,就新建一个连接对象给服务器让其使用,用完后销毁该创建的对象。
我的理解
就是,当你需要获取数据库连接时,你只需要创建一个连接池对象,定义好sql语句,给到连接池,就可以操作数据库。连接池对象就是个工具类,我们需要使用它就创建其对象,写好SQL语句就可实现操作数据库。数据库连接池中已经定义好了连接信息,而且我们可以通过修改其配置文件,实现不同数据之间的访问,也可以自定义最大连接量。
数据库连接池的好处
- 节约资源(不是关闭连接而是归还)
- 用户访问高效(直接获取连接对象,不用创建)
一个最基本的连接池:
public class PersonalConnectionPool {
/**
* 用户名
*/
private static String user;
/**
* 密码
*/
private static String password;
/**
* 连接数据库的URL
*/
private static String url;
/**
* 连接池
* 规定最大连接数为3
*/
private static LinkedList<Connection> pool;
/**
* 从属性文件中加载数据库驱动,初始化连接池
*/
static{
try {
Properties properties = new Properties();
pool = new LinkedList<Connection>();
Class.forName("com.mysql.jdbc.Driver");
ClassLoader classLoader = PersonalConnectionPool.class.getClassLoader();
InputStream iStream = classLoader.getResourceAsStream("mysqlCongfig.properties");
properties.load(iStream);
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
//创建三个连接对象(包装类对象)放到池子中
for (int i = 0; i < 3; i++) {
Connection connection = DriverManager.getConnection(url, user, password);
Connection connectionWrapper = new ConnectionWapper(connection,pool);
pool.add(connectionWrapper);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @throws SQLException
* @method 向外提供连接对象
*/
public Connection getConnection() throws SQLException {
Connection connection;
if(pool.size()>0)
{
connection = pool.removeFirst();
}
else
{
//等待超时,返回一个新创建的对象
connection = DriverManager.getConnection(url, user, password);
}
System.out.println("当前池子中有 "+pool.size()+" 个对象");
return connection;
}
/**
* 归还连接对象
* 直接简化在包装类的close方法中
*/
}
池子中用了到了一个包装类,包装了通过DriverManager.getConnection获取到的Connection的实现类对象,该包装也实现了Connection接口,重写了案例中需要的方法。该类结构如下:
public class ConnectionWapper implements Connection {
/**
* Connection接口的实现类对象的引用
*/
private Connection connection;
/**
* 存放连接包装对象的池子的引用
*
*/
private LinkedList<Connection> pool;
/**
*
* @param connection 的实现类对象
*/
public ConnectionWapper(Connection connection, LinkedList<Connection> pool) {
super();
this.connection = connection;
this.pool = pool;
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
PreparedStatement prepareStatement = connection.prepareStatement(sql);
return prepareStatement;
}
@Override
public void close() throws SQLException {
pool.add(this);
System.out.println("当前池子中有 "+pool.size()+" 个对象");
}
@Override
...
}
基于统一,JAVA为数据库连接池提供了公共接口,要求所有项目开发的连接池必须实现DataSource接口,可一统一用一套接口的方法使用不同开发商的数据库连接池。
常用连接池
dbcp连接池
- 封装dbcp连接池创建一个数据库工具类
/**
* (封装dbcp连接池来创建数据库工具类)
* (属性文件为源文件夹properties下的dbcpconfig.properties)
*/
public class DatabaseUtil {
/**
* 数据库连接池(dbcp连接池)对象引用
*/
private static DataSource dbcpPoor;
/**
* 只执行一次
*/
static {
Properties properties = new Properties();
ClassLoader classLoader = DatabaseUtil.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("dbcpconfig.properties");
try {
properties.load(resourceAsStream);
//通过直接创建连接池对象并设置参数方法创建连接池对象
// BasicDataSource basicDataSource = new BasicDataSource();
// basicDataSource.setUsername(properties.getProperty("username"));
// basicDataSource.setPassword(properties.getProperty("password"));
// basicDataSource.setDriverClassName(properties.getProperty("driverClassName"));
// basicDataSource.setUrl(properties.getProperty("url"));
//
// dbcpPoor = basicDataSource;
//通过工厂的方法创建连接池对象
dbcpPoor = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 获取连接对象
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
Connection connection = dbcpPoor.getConnection();
System.out.println("获取连接对象成功");
return connection;
}
/**
* 关闭资源
*/
//关闭建立的连接对象,释放资源
public static void closeSourceConnection(Connection connection, Statement statement, ResultSet resultSet){
try {
if (connection!=null) {
connection.close();
}
if (statement!=null) {
statement.close();
}
if (resultSet!=null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static DataSource getDbcpPoor() {
return dbcpPoor;
}
}
c3p0连接池
- 封装c3p0连接池创建一个数据库工具类
/**
* (封装c3p0连接池来创建数据库工具类)
* @author YanoHao
*
*/
public class DatabaseUtil {
/**
* c3p0连接池对象的引用
*/
private static DataSource c3p0Poor;
/**
* 创建一次
*/
static {
//直接创建连接池对象(自动加载配置文件,无需设置参数)
c3p0Poor = new ComboPooledDataSource();
//通过工厂的方式创建连接池对象
// try {
// DataSource unpooledDataSource = DataSources.unpooledDataSource();
// c3p0Poor = DataSources.pooledDataSource(unpooledDataSource);
// } catch (SQLException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
/**
* 获取连接对象
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
Connection connection = c3p0Poor.getConnection();
System.out.println("获取连接对象成功");
return connection;
}
/**
* 关闭资源
*/
//关闭建立的连接对象,释放资源
public static void closeSourceConnection(Connection connection, Statement statement, ResultSet resultSet){
try {
if (connection!=null) {
connection.close();
}
if (statement!=null) {
statement.close();
}
if (resultSet!=null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static DataSource getC3p0Poor() {
return c3p0Poor;
}
}
druid连接池
- 封装druid连接池创建一个数据库工具类
/*
* 封装druid连接池创建工具类
*/
public class DatabaseUtil {
/**
* 数据库连接池(druid连接池)对象引用
*/
private static DataSource druidPool;
static {
try {
Properties properties = new Properties();
ClassLoader classLoader = DatabaseUtil.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("druidconfig.properties");
properties.load(resourceAsStream);
//通过直接创建连接池对象的方式创建连接池对象
// DruidDataSource druidDataSource = new DruidDataSource();
// druidDataSource.setUsername(properties.getProperty("username"));
// druidDataSource.setPassword(properties.getProperty("password"));
// druidDataSource.setUrl(properties.getProperty("url"));
// druidDataSource.setDriverClassName(properties.getProperty("driverClassName"));
// druidPool = druidDataSource;
//通过工厂的方式创建连接池对象
druidPool = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException{
Connection connection = druidPool.getConnection();
return connection;
}
/**
*
* 关闭建立的连接对象,释放资源
*/
public static void closeSourceConnection(Connection connection, Statement statement, ResultSet resultSet){
try {
if (connection!=null) {
connection.close();
}
if (statement!=null) {
statement.close();
}
if (resultSet!=null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static DataSource getDruidPool() {
return druidPool;
}
}