一、什么是连接池?
数据库连接池负责分配,管理和释放数据库连接,允许程序重复使用一个现有的数据库连接,而不是重新创建一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术明显 提高对数据库操作的性能。具体看后续图1和图2进行对比:
传统获取连接方式:
应用程序直接获取连接的缺点: 用户每次请求都需要向数据库获得连接,而数据库创建连接通常需要消耗相对较大的资源,创建时间页较长。 假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源, 并且极易造成数据库服务器内存溢出、宕机。
采用连接池获取连接方式:
目的:解决建立数据库连接耗费资源和时间很多的问题,提高性能。
二、自定义数据库连接池
package com.qf.ownjdbc; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import javax.sql.DataSource; public class MyDtataSource implements DataSource{ private static List<Connection> list = new ArrayList<>(); static{ for (int i = 0; i < 3; i++) { //JDBCUtils 是自己定义的一个获取数据库连接的工具类,这里就不写了 JDBCUtils ju = new JDBCUtils(); Connection connection = ju.getConnection(); list.add(connection); } } //获取连接池的连接对象 @Override public Connection getConnection() throws SQLException { if (list.size() == 0) { for (int i = 0; i < 3; i++) { JDBCUtils ju = new JDBCUtils(); Connection connection = ju.getConnection(); list.add(connection); } } Connection connection = list.remove(0); return connection; } //归还用完后的连接对象 public boolean connBack(Connection connection) { if (list.size() < 3) { list.add(connection); return true;//如果连接池少于三个连接对象,就归还连接对象 } return false;//如果连接池有三个连接对象,就在调用连接对象的方法中close } @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; } }
三、装饰者模式(连接池)
/** * Connection:进行包装: 实现自己的关闭连接 ,重写其中的close() * * @author Administrator * *MyConnection: 装饰的成果 * *Connection:接口:被装饰者 * * *从数据源中获取连接: * */ public class MyConnection implements Connection { private Connection connection; private LinkedList<Connection> pool=null; public MyConnection(Connection connection, LinkedList<Connection> pool) { super(); this.connection = connection; this.pool = pool; } //释放了执行所需的资源,目前该连接没有任何操作; @Override public void close() throws SQLException { // TODO Auto-generated method stub //把用完的连接重新放入到连接池, pool.addLast(connection); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { // TODO Auto-generated method stub return connection.prepareStatement(sql); }
.........//这里还有其它继承与Connection 的放法 }
/** * 自定义DataSource数据源得到连接(MyConnection(包装类)), * * 备注:MyConnection包装类的作用主要是关闭连接 * @author Administrator * */ public class MyDataSource implements DataSource{ private static List<Connection> pool1= Collections.synchronizedList(new LinkedList<Connection>()); private static LinkedList<Connection> pool=new LinkedList<Connection>(pool1); //构造连接池 static{ for (int i = 0; i < 10; i++) { pool.add(DBUtils.getConnection()); } } @Override public Connection getConnection() throws SQLException { // TODO Auto-generated method stub if (pool.size()>0) { //从list取出一个连接,该connection无法关闭 Connection connection= pool.removeFirst(); //对connection进行包装,包装成MyConnection Connection connection2= new MyConnection(connection, pool); return connection2; } return null; } }
四、适配器模式(连接池)
public class BaseConnection implements Connection { private Connection connection; public BaseConnection(Connection connection) { super(); this.connection = connection; } @Override public void close() throws SQLException { // TODO Auto-generated method stub } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { // TODO Auto-generated method stub return connection.prepareStatement(sql); }
.........//这里还有其它继承与Connection 的放法
}
/** * 相比MyConnection而言,关注点在自己需要的方法上 * @author Administrator * */ public class MyConnection01 extends BaseConnection{ private LinkedList<Connection> pool=null; private Connection connection; public MyConnection01(Connection connection,LinkedList<Connection> pool) { super(connection); // TODO Auto-generated constructor stub this.connection=connection; this.pool =pool; } @Override public void close() throws SQLException { // TODO Auto-generated method stub pool.addLast(connection); } }
/** * 自定义DataSource数据源得到连接(MyConnection(包装类)), * * 备注:MyConnection包装类的作用主要是关闭连接 * @author Administrator * */ public class MyDataSource implements DataSource{ private static List<Connection> pool1= Collections.synchronizedList(new LinkedList<Connection>()); private static LinkedList<Connection> pool=new LinkedList<Connection>(pool1); //构造连接池 static{ for (int i = 0; i < 10; i++) { pool.add(DBUtils.getConnection()); } } @Override public Connection getConnection() throws SQLException { // TODO Auto-generated method stub if (pool.size()>0) { //从list取出一个连接,该connection无法关闭 Connection connection= pool.removeFirst(); //对connection进行包装,包装成MyConnection Connection connection2= new MyConnection(connection, pool); return connection2; } return null; } }
上面这些放法都是为了让我们熟悉原理,而我们在工作中一般都是用到框架,下面介绍DBCP与C3P0
五、DBCP
①配置文件(dbcpconfig.properties 文件放在 src 目录下)
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/day13 username=root password=123456 #<!-- 初始化连接 --> initialSize=10 #最大连接数量 maxActive=50 #<!-- 最大空闲连接 --> maxIdle=20 #<!-- 最小空闲连接 --> minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=utf8 #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的只读(read-only)状态。 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) defaultReadOnly= #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=REPEATABLE_READ
②导包问题(包都方法新建的 lib 目录下,并且导入)
package jdbc_dbcp; 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.BasicDataSourceFactory; public class DBUtils_dbcp { private static Properties properties = new Properties(); private static DataSource dataSource; static{ try { properties.load(DBUtils_dbcp.class.getClassLoader().getResourceAsStream("dbcpconfig.properties")); dataSource = BasicDataSourceFactory.createDataSource(properties); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static Connection getConnection() { try { return dataSource.getConnection(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
六、C3P0
--C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
--JNDI: 全称:Java Naming and Directory Interface,Java命名和目录接口,用它的好处是:程序员应该不需要关心“具体的数据库后台是什么?JDBC驱动程序是什么?JDBC URL格式是什么?访问数据库的用户名和口令是什么?”等等这些问题。而是把这些问题交给J2EE容器来配置和管理,程序员只需要对这些配置和管理进行引用即可。(只关心结果不管过程)
C3P0与DBCP区别:
--DBCP没有自动回收空闲连接的功能
--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://localhost/day02</property> <property name="user">root</property> <property name="password">123</property> <property name="checkoutTimeout">30000</property> <property name="idleConnectionTestPeriod">30</property> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">200</property> </default-config> </c3p0-config>
②导包问题
package jdbc_c3p0; import java.sql.Connection; import java.sql.SQLException; import com.mchange.v2.c3p0.ComboPooledDataSource; public class DButils_C3P0 { private static ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); public static Connection getConnection() { try { return comboPooledDataSource.getConnection(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
七、用JavaWeb服务器管理数据源:Tomcat
开发web应用,必须使用一个JavaWeb服务器,JavaWeb服务器都内置数据。
Tomcat:(默认是DBCP数据库连接池)
数据源只需要服务器配置即可
配置数据源的服务器步骤如下:
1.拷贝数据库连接驱动的jar到tomcat的lib目录下;
2.配置数据源XML文件; a)如果把配置信息写在tomcat下的conf目录的context.xml中,那么所有应用都能使用此数据源。 b)如果是在当前应用的META-INF中创建context.xml, 编写数据源,那么只有当前应用可以使用。 context.xml配置信息如下图:
根据name去查找配置信息得到数据源