连接池概念
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
通俗点讲,连接池就是一个存放连接池子,获取连接时候直接在池子中获取就可以了,当调用连接的close()方法时候也不是将资源释放,而是将连接归还到池子中,其他操作就可以再次使用该链接。
自定义连接池
在写自定义连接池之前应该先了解实现连接池的方式,java为数据库连接池提供了公共接口javax.sql.DataSource,连接池必须实现该接口。
分析:
- 实现javax.sql.DataSource接口
- 需要一个存放数据库连接的池子,因为连接池中连接主要进行频繁的获取和添加操作,所以使用LinkedList。
- 程序使用数据库时可能需要Connection和DataSource,所以需要getConnnection()和getDataSource()两个方法
- 当某个连接使用完毕后需要调用close()方法将连接归还给连接池,这是就需要增强close()方法
自定义连接池
package 数据库;
/***
* 自定义连接池
* @author zhang
*
*/
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.logging.Logger;
import javax.sql.DataSource;
public class MyDataSource implements DataSource {
// 数据库驱动程序
private static String driver = null;
// 数据库统一资源标识符
private static String url = null;
// 数据库用户名
private static String username = null;
// 数据库密码
private static String password = null;
// 创建连接池
private static LinkedList<Connection> pool = new LinkedList<Connection>();
// 预先读取配置文件并创建几个连接对象放到池子中
static {
try {
// 读取配置文件
InputStream is = MyDataSource.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties pro = new Properties();
pro.load(is);
driver = pro.getProperty("driver");
url = pro.getProperty("url");
username = pro.getProperty("username");
password = pro.getProperty("password");
Class.forName(driver);
if (is != null)
is.close();
// 预添加连接
for (int i = 0; i < 5; i++) {
pool.add(DriverManager.getConnection(url, username, password));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取连接
*
* @return
*/
@Override
public Connection getConnection() throws SQLException {
// 如果没有就在添加一部分
if (pool.isEmpty()) {
for (int i = 0; i < 5; i++) {
pool.add(DriverManager.getConnection(url, username, password));
}
}
return pool.removeFirst();
}
/**
* 连接对象归还到连接池中去
*/
public void releaseConnection(Connection con) {
pool.add(con);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public void setLogWriter(PrintWriter arg0) throws SQLException {
}
@Override
public void setLoginTimeout(int arg0) throws SQLException {
}
@Override
public boolean isWrapperFor(Class<?> arg0) throws SQLException {
return false;
}
@Override
public <T> T unwrap(Class<T> arg0) throws SQLException {
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
}
现在实现的自定义连接池还有很大的问题,按照上面的思路每次连接使用完之后就要调用releaseConnection方法将连接归还给连接池,但是一旦错误调用了close()方法将连接真实关闭,那么的话就无法将连接归还给连接池。如果我们希望将close()功能改造为将连接归还给连接池而不是释放资源,就要对close()方法进行增强。
方法增强参考:https://blog.csdn.net/qq_41345281/article/details/89073243
增强close()方法(装饰者模式)
public class MyConnection implements Connection {
private Connection con;
private LinkedList<Connection> pool;
public MyConnection(LinkedList<Connection> pool, Connection con) {
this.pool = pool;
this.con = con;
}
/**
* 需要增强的方法
*/
@Override
public void close() throws SQLException {
pool.add(con);
}
这样调用close方法就是将连接返还到连接池中了
c3p0连接池
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
使用c3p0需要导入相应jar包和c3p0-config.xml配置文件
导包:
配置文件
配置文件名称:c3p0-config.xml(文件名固定)
配置文件位置:src (类路径)
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>//默认配置
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/member</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">5</property>//初始连接个数
<property name="maxPoolSize">20</property>//最大连接个数
</default-config>
<named-config name="c3p0"> //命名配置
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web_07</property>
<property name="user">root</property>
<property name="password">123</property>
</named-config>
准备工作做好了现在就上代码
package 数据库;
/**
* c3p0工具类
* @author zhang
*
*/
import java.sql.Connection;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class c3p0Utils {
//使用默认配置
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
//使用命名配置
//private static ComboPooledDataSource dataSource = new ComboPooledDataSource("myc3p0");
/**
* 获取Datasource对象
*
* @return
*/
public static ComboPooledDataSource getDataSource() {
return c3p0Utils.dataSource;
}
/**
* 获取Connection对象
*
* @return
*/
public static Connection getConnection() {
try {
return c3p0Utils.dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException();
}
}
}
/**
* 释放资源
*
* @throws SQLException
*/
public static void close(Connection con, PreparedStatement prst, ResultSet re) throws SQLException {
if (con != null) {
con.close();
}
if (prst != null) {
prst.close();
}
if (re != null) {
re.close();
}
}
dbcp连接池
DBCP(DataBase Connection Pool)数据库连接池,是Java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。
导包:
配置文件
配置文件名称:*.properties
配置文件位置:建议src (类路径)
#JDBC\u8FDE\u63A5\u914D\u7F6E\u6587\u4EF6
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/member
username=root
password=root
实现的工具类
package 数据库;
/**
* dbcp
* @author zhang
*
*/
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class dbcpUtils {
private static DataSource datasource;
/**
* 读取配置文件
*/
static {
try {
InputStream is = dbcpUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties pro = new Properties();
pro.load(is);
datasource = BasicDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
throw new RuntimeException();
}
}
public static DataSource getDataSource() {
return datasource;
}
public static Connection getConnection() {
try {
return datasource.getConnection();
} catch (SQLException e) {
throw new RuntimeException();
}
}
/**
* 释放资源
*
* @throws SQLException
*/
public static void close(Connection con, PreparedStatement prst, ResultSet re) throws SQLException {
if (con != null) {
con.close();
}
if (prst != null) {
prst.close();
}
if (re != null) {
re.close();
}
}
}