连接池
数据库频繁的打开与关闭连接,大大的影响了程序的运行效率,我们需要预先创建一组连接,当需要的时候就取出用,用完就归还。
自定义连接池
需要有3个参数
- 初始化连接数目——这个表示预先分配的资源
- 最大连接数目——允许分配的最大连接数
- 当前使用的连接数目
获取连接过程
当程序需要一个连接时,先检查连接池里面是否还有资源,预先创建的连接资源是否都已经分配,如果连接池里的资源还有就直接获得连接池里面的连接,如果连接池里的资源都已经分配了,就检查当前连接是否超过最大连接数,如果小于最大连接数目就再新建一个连接并分配,如果大于等于最大连接数目就抛出异常,不能再分配连接给该程序了。
释放连接过程
当程序使用完连接,需要释放资源时,先查看连接池里的连接是否小于初始化的值,如果小于预分配的连接就直接放到连接池中(不执行close),如果连接池的资源已经达到预分配的资源就close该连接。
public class MyPool {
private int init_count = 3; //初始化连接数目
private int max_count = 6; //最大连接数目
//指当前已经创建的连接
private int current_count = 0; //当前使用的连接数
//连接池
private LinkedList<Connection> pool = new LinkedList<Connection>();
//构造函数中,初始化连接放入连接池
public MyPool() {
for(int i = 0; i < init_count; i++) {
current_count++;
pool.add(createConnection());
}
}
//得到连接的方法
public Connection createConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "huping");
return conn;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
//获取连接
public Connection getConnection() {
//判断连接池中是否有连接,有连接则
if(pool.size() > 0) {
return pool.removeFirst();
}
//连接池中没有连接,判断当前连接数是否已经超过最大连接数目,没有超过则
if(current_count < max_count) {
current_count++;
return createConnection();
}
//超过了最大连接数
throw new RuntimeException("当前连接已经达到最大数目");
}
//释放连接
public void realeaseConnection(Connection conn) {
//判断当前连接池的数目是否小于初始化连接池的数目
if(pool.size() < init_count) {
pool.add(conn);
} else {
//关闭连接
try {
current_count--;
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyPool pool = new MyPool();
//System.out.println("当前连接:"+pool.current_count);
//使用连接
Connection conn1 = pool.getConnection();
Connection conn2 = pool.getConnection();
Connection conn3 = pool.getConnection();
Connection conn4 = pool.getConnection();
Connection conn5 = pool.getConnection();
Connection conn6 = pool.getConnection();
//释放连接
pool.realeaseConnection(conn1);
System.out.println("连接池的数目:"+pool.pool.size());
System.out.println("当前连接:"+pool.current_count);
}
}
工具
DBCP
DBCP(database connection pool)是 Apache 软件基金组织下的开源连接池实现。Tomcat 的连接池正是采用该连接池来实现的。
使用时需要添加2个包
commons-dbcp2-2.1.1.jar
commons-pool2-2.4.2.jar
public class DBCPDemo {
/**
* 硬编码方式
*/
@Test
public void testDbcp1(){
//创建DBCP连接池工具
BasicDataSource dataSource = new BasicDataSource();
//设置参数
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("huping");
dataSource.setInitialSize(3);//设置连接池的初始值
dataSource.setMaxTotal(4);//设置连接池的最大连接
dataSource.setMaxIdle(3000);//最大空闲时间
//获取连接
try {
Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement("select * from student where id=2");
ResultSet rs = ps.executeQuery();
rs.next();
System.out.println(rs.getString("name"));
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 通过配置文件实现
*/
@Test
public void testDbcp2(){
Properties prop = new Properties();
InputStream in = DBCPDemo.class.getResourceAsStream("db_dbcp.properties");
try {
prop.load(in);
DataSource dataSource = BasicDataSourceFactory.createDataSource(prop);
Connection conn = dataSource.getConnection();
// 获得连接成功
System.out.println(conn);
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
properties配置文件
url=jdbc:mysql://localhost:3306/test
driverClassName=com.mysql.jdbc.Driver
username=root
password=huping
initialSize=3
maxTotal=6
maxIdle=3000
C3P0
Spring框架,默认支持C3P0连接池技术
需要导入c3p0-0.9.1.2.jar
public class C3P0Demo {
/**
* 硬编码方式
*/
@Test
public void testC3p0_code() throws Exception{
//创建c3p0连接池工具
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//设置参数
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUser("root");
dataSource.setPassword("huping");
dataSource.setInitialPoolSize(3);
dataSource.setMaxPoolSize(6);
dataSource.setMaxIdleTime(3000);
//获取连接
Connection conn = dataSource.getConnection();
System.out.println(conn);
PreparedStatement ps = conn.prepareStatement("select * from student where id=2");
ResultSet rs = ps.executeQuery();
rs.next();
System.out.println(rs.getString("name"));
conn.close();
}
/**
* 通过xml文件实现
* @throws SQLException
*/
@Test
public void testC3p0_xml() throws SQLException{
//会自动加载src下的配置文件 c3p0-config.xml 可以有一个参数,指定配置(mysql或者oracle),没有参数就是默认配置
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//获取连接
Connection conn = dataSource.getConnection();
System.out.println(conn);
PreparedStatement ps = conn.prepareStatement("select * from student where id=2");
ResultSet rs = ps.executeQuery();
rs.next();
System.out.println(rs.getString("name"));
conn.close();
}
}
xml配置文件(该文件要放在src下,才会自动被加载)
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="user">root</property>
<property name="password">huping</property>
<property name="initialPoolSize">3</property>
<property name="maxPoolSize">6</property>
<property name="maxIdleTime">3000</property>
</default-config>
<!--
<named-config name="dumbTestConfig">
<property name="maxStatements">200</property>
<property name="jdbcUrl">jdbc:test</property>
<user-overrides user="poop">
<property name="maxStatements">300</property>
</user-overrides>
</named-config>
-->
</c3p0-config>