数据库连接池

原创 2016年08月29日 20:50:21

应用程序直接获取数据库连接的缺点

用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。如下图所示:
这里写图片描述

使用数据库连接池优化程序性能

数据库连接池的基本概念

数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标,数据库连接池正是针对这个问题提出来的。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。如下图所示:
这里写图片描述
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
数据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:

  1. 最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费。
  2. 最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作。
  3. 如果最小连接数与最大连接数相差很大:那么最先连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,他将被放到连接池中等待重复使用或是空间超时后被释放。

编写数据库连接池

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

  • Connection getConnection()
  • Connection getConnection(String username, String password)

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

  1. 在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
  2. 实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。
  3. 当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。Collection保证将自己返回到LinkedList中是此处编程的难点

我们先来思考这样一个问题:数据库连接池一上来就要找数据库要一批连接,所以应该要使用一个集合来保存这些连接,该集合要设计成什么类型的集合,设计成ArrayList集合吗?
答:肯定不行,等一会要从集合里面取连接,还要往集合里面还连接,涉及到集合的大量的增删,如果你用ArrayList集合,ArrayList集合底层实现使用的是数组,数组的增删效率是比较差的;所以应该用LinkedList集合,LinkedList集合底层实现使用的是链表,这样增删就没有性能问题。
所以按照以上步骤一我们应该设计一个如下的静态字段:

private static LinkedList<Connection> list = new LinkedList<Connection>();

接着我们按照步骤二来实现getConnection方法,如下实现getConnection方法的代码是错误的!

public Connection getConnection() throws SQLException {

    if (list.size() <= 0) {
        throw new RuntimeException("数据库忙,请稍会再来!!!");
    }

    /*
     * 千万不能调用list的get()方法取连接。
     * 调用list的get()方法取连接,返回的只是这个连接的引用,但连接还在集合里面,
     * 这就不行,我们说的取一个连接是从集合取了一个连接之后,再将其删掉。
     */
    Connection conn = list.get(1);

    return conn;
}

原因是:调用list的get()方法取连接,返回的只是这个连接的引用,但连接还在集合里面,这就不行,我们说的取一个连接是从集合取了一个连接之后,再将其删掉。所以千万不能调用list的get()方法取连接。
一般来说,我们自己编写一个数据库连接池,首次编写的代码都会是如下这样:

public class DBConnectionPool implements DataSource {

    /*
     * 数据库连接池一上来就要找数据库要一批连接,所以应该要使用一个集合来保存这些连接,
     * 该集合要设计成什么类型的集合,设计成ArrayList集合吗?
     * 肯定不行,等一会要从集合里面取连接,还要往集合里面还连接,涉及到集合的大量的增删,
     * 如果你用ArrayList集合,ArrayList集合底层实现使用的是数组,数组的增删效率是比较差的;
     * 所以应该用LinkedList集合,LinkedList集合底层实现使用的是链表,这样增删就没有性能问题。
     */
    private static LinkedList<Connection> list = new LinkedList<Connection>();

    private static Properties config = new Properties();

    // 静态代码块只执行一次,因为静态代码块在类加载时执行,类永远只加载一次
    static {
        try {
            config.load(DBConnectionPool.class.getClassLoader().getResourceAsStream("db.properties"));
            Class.forName(config.getProperty("driver"));
            for (int i = 0; i < 10; i++) {
                // MySQL驱动返回的Connection,实现了java.sql.Connection接口
                Connection conn =  DriverManager.getConnection(config.getProperty("url"), config.getProperty("username"), config.getProperty("password"));
                list.add(conn);
            }
        } catch (Exception e) {
            /*
             * db.properties文件无法读取,那么整个应用程序无法连接数据库,
             * 驱动都加载不了,那么整个应用程序都无法工作,
             * 所以都应该抛一个错误(ExceptionInInitializerError)
             */
            throw new ExceptionInInitializerError(e);
        }

    }

    @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() throws SQLException {

        if (list.size() <= 0) {
            throw new RuntimeException("数据库忙,请稍会再来!!!");
        }

        /*
         * 千万不能调用list的get()方法取连接。
         * 调用list的get()方法取连接,返回的只是这个连接的引用,但连接还在集合里面,
         * 这就不行,我们说的取一个连接是从集合取了一个连接之后,再将其删掉。
         */
        Connection conn = list.get(1);

        return conn;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

}

经过以上的分析,可知以上实现getConnection方法的代码是错误的!现在我们修改实现getConnection方法的代码如下:

public Connection getConnection() throws SQLException {

    if (list.size() <= 0) {
        throw new RuntimeException("数据库忙,请稍会再来!!!");
    }

    /*
     * 千万不能调用list的get()方法取连接。
     * 调用list的get()方法取连接,返回的只是这个连接的引用,但连接还在集合里面,
     * 这就不行,我们说的取一个连接是从集合取了一个连接之后,再将其删掉。
     */
    // Connection conn = list.get(1);

    Connection conn = list.removeFirst();

    return conn;
}

那么这样是不是就万事大吉了呢?显然不是。直接将连接返回出去,就会产生一个问题,别人在该连接上操作完数据库之后,他经常会调用连接的close()方法,一调用close()方法,连接就会还给数据库,这就不行了。我们这个数据库连接池要设计成别人一调用close()方法,连接就要还给数据库连接池。这就归结为一个问题:Connection的close()满足不了我们的需求,不够我们用了,这时就要增强Connection的close()方法——别人一调用close()方法,连接就要还给数据库连接池。
别人从连接池中获得连接与数据库进行通讯,一般都会这样做:

public class Demo {

    public static void main(String[] args) throws SQLException, InterruptedException {

        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            DBConnectionPool pool = new DBConnectionPool();
            conn = pool.getConnection();

            // conn ......... 在该连接上做操作,做完操作之后要释放连接

        } finally {
            JdbcUtils_DBCP.release(conn, st, rs);
        }
    }

}

产生问题之后,我们就要解决问题,那又该怎样搞定此问题呢?
在实际开发中,发现某个对象的方法不够使了(满足不了开发需求时),就要对某个对象的方法进行增强,这在java里面通常有3种解决方式。

  • 写一个Connection的子类,覆盖close()方法,增强close()方法。
    必须将原有对象的信息导入到子类里面来,如果信息不好导入,这是就不能用这种方式。反之,这种方式只适合对象没有什么信息。
  • 用包装设计模式。
    将来在实际开发里面,都是在服务器下做开发,那服务器经常会给你传很多对象过来,有时候服务器扔给你一个对象,你发现这个对象满足不了你的需求,你就要增强了,你这时用子类的方式通常来说是不行的,因为服务器传递给你的对象封装了很多其他信息,你用子类对象增强,你就要把信息复制到子类对象里面去,这通常是不可能完成的任务,因为你不知道那个对象里面有什么信息,所以你无法复制。这时就要用到包装设计模式!!!
  • 用动态代理(spring aop——面向切面编程)。
    终极解决方案是动态代理!
    动态代理——拦截你对真实业务对象的访问,采用拦截的方式进行增强。

现在我们使用第一种方式,代码通常都会这样编写:

public class DBConnectionPool implements DataSource {

    /*
     * 数据库连接池一上来就要找数据库要一批连接,所以应该要使用一个集合来保存这些连接,
     * 该集合要设计成什么类型的集合,设计成ArrayList集合吗?
     * 肯定不行,等一会要从集合里面取连接,还要往集合里面还连接,涉及到集合的大量的增删,
     * 如果你用ArrayList集合,ArrayList集合底层实现使用的是数组,数组的增删效率是比较差的;
     * 所以应该用LinkedList集合,LinkedList集合底层实现使用的是链表,这样增删就没有性能问题。
     */
    private static LinkedList<Connection> list = new LinkedList<Connection>();

    private static Properties config = new Properties();

    // 静态代码块只执行一次,因为静态代码块在类加载时执行,类永远只加载一次
    static {
        try {
            config.load(DBConnectionPool.class.getClassLoader().getResourceAsStream("db.properties"));
            Class.forName(config.getProperty("driver"));
            for (int i = 0; i < 10; i++) {
                // MySQL驱动返回的Connection,实现了java.sql.Connection接口
                Connection conn =  DriverManager.getConnection(config.getProperty("url"), config.getProperty("username"), config.getProperty("password"));
                list.add(conn);
            }
        } catch (Exception e) {
            /*
             * db.properties文件无法读取,那么整个应用程序无法连接数据库,
             * 驱动都加载不了,那么整个应用程序都无法工作,
             * 所以都应该抛一个错误(ExceptionInInitializerError)
             */
            throw new ExceptionInInitializerError(e);
        }

    }

    @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() throws SQLException {

        if (list.size() <= 0) {
            throw new RuntimeException("数据库忙,请稍会再来!!!");
        }

        /*
         * 千万不能调用list的get()方法取连接。
         * 调用list的get()方法取连接,返回的只是这个连接的引用,但连接还在集合里面,
         * 这就不行,我们说的取一个连接是从集合取了一个连接之后,再将其删掉。
         */
        // Connection conn = list.get(1);

        Connection conn = list.removeFirst();

        MyConnection my = new MyConnection(); // MyConnection要想真正的连数据库, 那么MyConnection要封装连哪个数据库、用什么用户名和密码

        return my;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

    class MyConnection extends com.mysql.jdbc.Connection { // 继承MySQL驱动返回的Connection
        public void close() {
            // ......
        }
    }

}

很显然第一种方式是不行的!因为MyConnection要想真正的连数据库, 那么MyConnection要封装连哪个数据库、用什么用户名和密码。
现在我们来使用第二种方式——用包装设计模式,使用包装设计模式可分成以下几个步骤:

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

我们要是用了包装设计模式,那么代码通常都会这样写:

public class DBConnectionPool implements DataSource {

    /*
     * 数据库连接池一上来就要找数据库要一批连接,所以应该要使用一个集合来保存这些连接,
     * 该集合要设计成什么类型的集合,设计成ArrayList集合吗?
     * 肯定不行,等一会要从集合里面取连接,还要往集合里面还连接,涉及到集合的大量的增删,
     * 如果你用ArrayList集合,ArrayList集合底层实现使用的是数组,数组的增删效率是比较差的;
     * 所以应该用LinkedList集合,LinkedList集合底层实现使用的是链表,这样增删就没有性能问题。
     */
    private static LinkedList<Connection> list = new LinkedList<Connection>();

    private static Properties config = new Properties();

    // 静态代码块只执行一次,因为静态代码块在类加载时执行,类永远只加载一次
    static {
        try {
            config.load(DBConnectionPool.class.getClassLoader().getResourceAsStream("db.properties"));
            Class.forName(config.getProperty("driver"));
            for (int i = 0; i < 10; i++) {
                // MySQL驱动返回的Connection,实现了java.sql.Connection接口
                Connection conn =  DriverManager.getConnection(config.getProperty("url"), config.getProperty("username"), config.getProperty("password"));
                list.add(conn);
            }
        } catch (Exception e) {
            /*
             * db.properties文件无法读取,那么整个应用程序无法连接数据库,
             * 驱动都加载不了,那么整个应用程序都无法工作,
             * 所以都应该抛一个错误(ExceptionInInitializerError)
             */
            throw new ExceptionInInitializerError(e);
        }

    }

    @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() throws SQLException {

        if (list.size() <= 0) {
            throw new RuntimeException("数据库忙,请稍会再来!!!");
        }

        /*
         * 千万不能调用list的get()方法取连接。
         * 调用list的get()方法取连接,返回的只是这个连接的引用,但连接还在集合里面,
         * 这就不行,我们说的取一个连接是从集合取了一个连接之后,再将其删掉。
         */
        // Connection conn = list.get(1);

        Connection conn = list.removeFirst();

        /*
        MyConnection my = new MyConnection(); // MyConnection要想真正的连数据库, 那么MyConnection要封装连哪个数据库、用什么用户名和密码
        return my;
        */

        MyConnection my = new MyConnection(conn);

        return my;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

    class MyConnection implements Connection {
        private Connection conn;
        public MyConnection (Connection conn) {
            this.conn = conn;
        }
        @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 Statement createStatement() throws SQLException {
            return this.conn.createStatement();
        }

        @Override
        public PreparedStatement prepareStatement(String sql) throws SQLException {
            return this.conn.prepareStatement(sql);
        }

        @Override
        public CallableStatement prepareCall(String sql) throws SQLException {
            return this.conn.prepareCall(sql);
        }

        @Override
        public String nativeSQL(String sql) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void setAutoCommit(boolean autoCommit) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public boolean getAutoCommit() throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void commit() throws SQLException {
            this.conn.commit();
        }

        @Override
        public void rollback() throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public void close() throws SQLException {
            list.add(this.conn);
        }

        @Override
        public boolean isClosed() throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public DatabaseMetaData getMetaData() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void setReadOnly(boolean readOnly) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public boolean isReadOnly() throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void setCatalog(String catalog) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public String getCatalog() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void setTransactionIsolation(int level) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public int getTransactionIsolation() throws SQLException {
            // TODO Auto-generated method stub
            return 0;
        }

        @Override
        public SQLWarning getWarnings() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void clearWarnings() throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
                throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
                throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public Map<String, Class<?>> getTypeMap() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public void setHoldability(int holdability) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public int getHoldability() throws SQLException {
            // TODO Auto-generated method stub
            return 0;
        }

        @Override
        public Savepoint setSavepoint() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public Savepoint setSavepoint(String name) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void rollback(Savepoint savepoint) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public void releaseSavepoint(Savepoint savepoint) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
                throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
                int resultSetHoldability) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
                int resultSetHoldability) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public Clob createClob() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public Blob createBlob() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public NClob createNClob() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public SQLXML createSQLXML() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public boolean isValid(int timeout) throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void setClientInfo(String name, String value) throws SQLClientInfoException {
            // TODO Auto-generated method stub

        }

        @Override
        public void setClientInfo(Properties properties) throws SQLClientInfoException {
            // TODO Auto-generated method stub

        }

        @Override
        public String getClientInfo(String name) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public Properties getClientInfo() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void setSchema(String schema) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public String getSchema() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void abort(Executor executor) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
            // TODO Auto-generated method stub

        }

        @Override
        public int getNetworkTimeout() throws SQLException {
            // TODO Auto-generated method stub
            return 0;
        }

    }

    /*
    class MyConnection extends com.mysql.jdbc.Connection { // 继承MySQL驱动返回的Connection
        public void close() {
            // ......
        }
    } 
    */

}

在外面程序里面一调用DBConnectionPool的getConnection()方法,拿到的是MyConnection,然后调用MyConnection的prepareStatement(String sql)、commit()、createStatement()等方法,但是只要一调用close()方法,即将包装的connection还到数据库连接池里面去了。所以第二种方式是可行的!
但是你会发现定义一个类(MyConnection)去实现与被增强对象相同的接口(Connection),那么就需要实现这个接口里面所有的方法,可是这个接口(Connection)里面有太多太多的方法,那么我们就要一个个实现,这样写代码就像一个傻逼一样。我们绝不当傻逼!
现在就只剩下第三种方式——用动态代理。终极解决方案也是动态代理!由于我们还没学这种技术,所以留待以后详解,但还是将数据库连接池核心代码放在这儿:
使用动态代理技术构建连接池中的connection

proxyConn = (Connection) Proxy.newProxyInstance(this.getClass()
        .getClassLoader(), conn.getClass().getInterfaces(),
        new InvocationHandler() {
        // 此处为内部类,当close方法被调用时将conn还回池中,其它方法直接执行
        public Object invoke(Object proxy, Method method,
                  Object[] args) throws Throwable {
            if (method.getName().equals("close")) {
                pool.addLast(conn);
                return null;
        }
        return method.invoke(conn, args);
    }
});
版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

数据库连接池--DBCP连接池

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

数据库连接池--C3P0连接池

c3p0是一个开源的jdbc连接池,hibernate 默认支持该数据源 jar文件: c3p0-0.9.2-pre5.jar mchange-commons-java-0.2.3.jar基...

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

数据库连接池 DBCP和c3p0数据库连接池

一、数据库连接池 1. 什么是连接池 传统的开发模式下,Servlet处理用户的请求,找Dao查询数据,dao会创建与数据库之间的连接,完成数据查询后会关闭数据库的链接。 这样的方式会导致用户每...

数据库连接池 以及 c3p0 数据库连接池

一:什么是数据库连接池 数据库连接池技术的出现是为了优化数据库连接操作的性能。水池中有水,需要时直接去取,电池中有电,需要用电时直接去取,那么数据库连接池里有很多数据库连接,当我们需要数据库连接时,不...

数据库连接池

最近监理的一个项目老是出现数据库莫名断开的问题,后来查明原因是由于使用的开发的数据库连接池出现的问题,那我就简单谈谈什么是数据库连接池及期原理。      对于一个简单的数据库应用,由于对于数据库的...

数据库连接池

本文转载:http://www.blogjava.net/hank/archive/2008/06/15/208058.html  数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程...

数据库连接池

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏...

数据库连接池

一、连接池原理:(面试)目的:解决建立数据库连接耗费资源和时间很多的问题,提高性能。二、编写标准的数据源自定义数据库连接池要实现javax.sql.DataSource接口,一般都叫数据源。三、编写数...

数据库连接池

package pool; /** * 这是外部可以配置的连接池属性 * 可以允许外部配置,拥有默认值 * @author Ran * */ public class DBbe...

数据库连接池

提出:数据库开发中存在问题,每次客户请求,在服务器端都单独创建一个连接操作数据库,当并发访问量非常大,很容易造成内存溢出,而且创建连接、释放连接资源非常消耗服务器性能。 原理: 在服务器端一次性创建多...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)