连接池的好处:
当使用java.sql中提供的api创建数据库连接时候,需要耗费很大的资源,要进行用户名密码数据库连接验证等,即耗费资源也耗费时间。如果在程序中,每次需要访问数据库时候,都进行数据库连接,那么势必会造成性能低下;同时,如果用户失误忘记释放数据库连接,会导致资源的浪费等。而数据库连接池就是解决该问题,通过管理连接池中的多个连接对象(connection),实现connection重复利用。从而,大大提高了数据库连接方面的性能。
连接池的功能:
负责创建,管理,释放,分配数据库连接即(connection)。首先,负责创建相应数目的数据库连接对象(connection),并存放到数据库连接池中。当用户请求数据库连接时,该连接池负责分配某个处于空闲状态的数据库连接对象;当用户发出释放该数据库连接时,该连接池负责将该连接对象重新设置为空闲状态,以便被别的请求重复利用。同时数据库连接池负责检查(空闲时间>最大空闲时间)的数据库连接,并释放。
自定义连接池
第一步:创建连接池实现(数据源),并实现接口javax.sql.DataSource,因为我们只使用该接口中的getConnection()方法供外界使用
第二步:提供一个集合,用于存放连接,因为移除/添加操作过多,所以选择LinkedList,提高效率
第三步:之后程序如果需要连接,则直接调用实现类的getConnection(),本方法将从连接池(容器List)获取连接,为了保证当前连接只给一个线程使用,所以我们需要将连接先从连接池中移除
第四步:当用户使用完连接,释放资源时,将连接重新归还到连接池中
创建数据源
package cn.datasource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import javax.sql.DataSource;
import cn.jdbc.JDBCUtils2;
public class MyDataSource implements DataSource {
//创建连接池
private static List<Connection> pool = new LinkedList<Connection>();
//通过静态代码块创建五个连接对象
static {
for(int i =0;i<5;i++)
{
//这里的JDBCUtils2.getConnection()是我们获取连接的自定义方法
//将该方法获取的连接放到连接池中
Connection conn = JDBCUtils2.getConnection();
pool.add(conn);
}
}
@Override
public Connection getConnection() throws SQLException {
//这里的话要进行判断是否为空,因为这里是外界获取Connection对象的途径
Connection conn = null;
if(pool.size()==0)
{
for(int i =0;i<5;i++)
{
conn = JDBCUtils2.getConnection();
pool.add(conn);
}
}
//这里表示的意思是每次进来都使用的是连接池中的第一个对象
conn = pool.remove(0);
return conn;
}
//归还对象到连接池中
public void backConnection(Connection conn)
{
pool.add(conn);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO Auto-generated method stub
return null;
}
}
使用
public class TestMyDataSource {
/**
* 添加用户
* 使用未改造过的connection
*/
@Test
public void testAddUser() {
Connection conn = null;
PreparedStatement pstmt = null;
// 1.创建自定义连接池对象
MyDataSource dataSource = new MyDataSource();
try {
// 2.从池子中获取连接
conn = dataSource.getConnection();
String sql = "insert into tbl_user values(null,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "吕布");
pstmt.setString(2, "貂蝉");
int rows = pstmt.executeUpdate();
if (rows > 0) {
System.out.println("添加成功!");
} else {
System.out.println("添加失败!");
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
dataSource.backConnection(conn);
}
}
外部工具类(c3p0也是目前使用最多的)
要记得导入架包
使用c3p0时要导入配置文件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:///web08</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="itheima">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web08</property>
<property name="user">root</property>
<property name="password">root</property>
</named-config>
</c3p0-config>
这里的xml有俩个配置,一个是默认配置,一个是通过名称调用的配置
ComboPooledDataSource dataSource = new ComboPooledDataSource();
ComboPooledDataSource dataSource = new ComboPooledDataSource("itheima");
没有参数的就是调用默认配置,有参数的就是调用有名字的配置
这里的话主要是使用dataSource.getConnection()来给程序使用获取连接
我们可以将其书写成一个工具类,方便使用,减少主程序书写时的代码量
自定义工具类(C3P0Utils)
package cn.itheima.jdbc.utils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Utils {
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("itheima");
public static DataSource getDataSource() {
return dataSource;
}
public static Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
使用时
public class TestC3P0 {
@Test
public void testAddUser1() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
// 2.从池子中获取连接
conn = C3P0Utils.getConnection();
String sql = "insert into tbl_user values(null,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "吕布3");
pstmt.setString(2, "貂蝉3");
int rows = pstmt.executeUpdate();
if (rows > 0) {
System.out.println("添加成功!");
} else {
System.out.println("添加失败!");
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JDBCUtils_V3.release(conn, pstmt, null);
}
}
DBCP连接池
导入架包
DBCP不能使用xml进行文件的配置,只能使用配置文件 .properties文件
常见配置项
db.properties配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/web08?useUnicode=true&characterEncoding=utf8
username=root
password=123456
使用的时候
这里的话是封装成了工具类方便使用
package cn.jdbc;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
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 {
//1.加载properties文件的输入流
InputStream is = DBCPUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties ps = new Properties();
//2.加载输入流
ps.load(is);
//3.创建数据源
dataSource = BasicDataSourceFactory.createDataSource(ps);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static DataSource getDataSource()
{
return dataSource;
}
public static Connection getConnection()
{
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}