数据库连接池

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库连接池相关的知识,希望对你有一定的参考价值。

手动编写连接池需实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:(JDK API)

  Connection getConnection()

  Connection getConnection(String username, String password)

实现DataSource接口,并实现连接池功能的步骤:

  1. 在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。

  2. 实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。

  3. 当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。

    4. Collection保证将自己返回到LinkedList中是此处编程的难点。

  所以为了让连接用完返回给LinkedList集合,而不是返还给数据库,必须要增强connection的close方法

     //增强 close方法,conn.close()
  在实际开发,发现对象的方法满足不了开发需求时,有三种方式对其进行增强
  1.写一个connecton子类,覆盖close方法,增强close方法
  2.用包装设计模式
  3.用动态代理 aop 面向切面编程

这里不可以用子类的方法来做,因为connection里面封装了很多其他信息,程序中还会用到connection的其他信息,所以如果用子类的方法基本不可能,等同于要重新写jdbc的驱动了。

 

包装设计模式增强close方法步骤:

   1.定义一个类,实现与被增强相同的接口
   2.在类中定义一个变量,记住被增强对象
   3.定义一个构造函数,接收被增强对象
   4.覆盖想增强的方法
   5.对于不想增强的方法,直接调用目标对象(被增强对象)的方法

 

class MyConnection implements Connection{
        private Connection conn;
        public MyConnection(Connection conn){
            this.conn = conn;
        }
        public void close(){
            list.add(this.conn);
        }
        public void clearWarnings() throws SQLException {
            this.conn.clearWarnings();
            
        }

.......

 

最好的解决办法是动态代理。采用拦截技术。AOP,面向切面编程

 

开源数据库连接池:数据库连接池也叫数据源

现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的实现,即连接池的实现。

通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。


也有一些开源组织提供了数据源的独立实现:
  DBCP 数据库连接池
  C3P0 数据库连接池

实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。程序员编程时也应尽量使用这些数据源的实现,以提升程序的数据库访问性能。

TOMCAT内置的连接池就是DBCP,tomcat是Apache的,dbcp也是apache的。

 

 

DBCP数据源:

DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:

  Commons-dbcp.jar:连接池的实现

  Commons-pool.jar:连接池实现的依赖库

Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。

 

dbcpconfig.properties封装了DBCP数据源的一些配置信息,包括数据库连接,连接数等。
一般放在src文件夹下
public class JdbcUtils_DBCP {
    
    private static DataSource ds = null;
    static{
        try{
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties prop = new Properties();
            prop.load(in);
            
            BasicDataSourceFactory factory = new BasicDataSourceFactory();
            ds = factory.createDataSource(prop);
        }catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public static Connection getConnection() throws SQLException{
        return ds.getConnection();//从连接池中拿连接,这个连接肯定也是增强过的,因为该连接用完还要还给连接池。
    }
    
    
    public static void release(Connection conn,Statement st,ResultSet rs){
        
        if(rs!=null){
            try{
                rs.close();   //throw new 
            }catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if(st!=null){
            try{
                st.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
            st = null;
        }
        if(conn!=null){
            try{
                conn.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        
    }
}    

在开发中可以通过上面的连接池来获取连接,释放连接。

 

 

C3P0数据源:Spring内置的连接池就是C3P0

导入C3P0的两个jar包

  c3p0.....jar

  mchang-commons.jar

c3p0-config.xml 连接池的配置文件,一般放在src目录下,详情查看c3p0的文档

 

<?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/day16</property>
        <property name="user">root</property>
        <property name="password">root</property>
        
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
        
        
    </default-config>

    <named-config name="flx">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property>
        <property name="user">root</property>
        <property name="password">root</property>
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </named-config>

</c3p0-config>

 

public class JdbcUtils_C3P0 {
    
    private static ComboPooledDataSource ds = null;
    static{
        try{
            ds = new ComboPooledDataSource();
        }catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public static Connection getConnection() throws SQLException{
        return ds.getConnection();
    }
    
    
    public static void release(Connection conn,Statement st,ResultSet rs){
        
        if(rs!=null){
            try{
                rs.close();   //throw new 
            }catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if(st!=null){
            try{
                st.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
            st = null;
        }
        if(conn!=null){
            try{
                conn.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        
    }
}    

 

 

配置TOMCAT数据库连接池:

使用tomcat的时候,可以不必要加入第三方连接池,tomcat内置了一个连接池, 如果希望tomcat

为你的应用程序创建连接池,需要对tomcat做配置。

<Context>
  <Resource name="jdbc/datasource" auth="Container"
            type="javax.sql.DataSource" username="root" password="root"
            driverClassName="com.mysql.jdbc.Driver" 
           url="jdbc:mysql://localhost:3306/jdbc"
            maxActive="8" maxIdle="4"/>
</Context>

只要对tomcat做了上面的配置,tomcat启动的时候就会为你的应用程序创建连接池,并且tomcat会把创建的连接池以JNDI的形式绑定到一个uri上面去,

name="jdbc/datasource",只要用的时候使用这个名称在JNDI中检索就可以啦。

以上配置可以在tomcat-config里的server.xml里

也可以在WebRoot-META-INF文件夹下新建一个context.xml里配置

可以参考tomcat的主页里的JNDI-COnfigration

 

在程序中就可以使用JNDI的方式去向连接池要连接了。

 

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
dataSource = (DataSource)envCtx.lookup("jdbc/datasource");

特别提醒:此种配置下,驱动jar文件需放置在tomcat的lib下

 

JNDI(Java Naming and Directory Interface),Java命名和目录接口,它对应于J2SE中的javax.naming包,

这套API的主要作用在于:它可以把Java对象放在一个容器中(JNDI容器),并为容器中的java对象取一个名称,以后程序想获得Java对象,只需通过名称检索即可。

其核心API为Context,它代表JNDI容器,其lookup方法为检索容器中对应名称的对象。

 

public class JdbcUtils_Tomcat {
    private static DataSource ds;
    static {
        try {
            Context initCtx = new InitialContext();
            Context envCtx = (Context) initCtx.lookup("java:comp/env");
            ds = (DataSource) envCtx.lookup("jdbc/EmployeeDB");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static Connection getConnection() throws SQLException{
        return ds.getConnection();
    }
}

在程序中就可以使用上面的工具类来向tomcat内置的数据源要连接。

 

以上是关于数据库连接池的主要内容,如果未能解决你的问题,请参考以下文章

newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段

连接池报错 Proxool Provider unable to load JAXP configurator file: proxool.xml

MySQL与Redis数据库连接池介绍(图示+源码+代码演示)

稳定性 耗时 监控原因分析-- dubbo rpc 框架 的线程池,io 连接模型. 客户端,服务端

基于UniDac的数据库连接池

数据库连接池的Java连接池