数据库连接池规范

数据库连接池规范

上节是我们模拟编写了一个数据库连接池,对于不同的开发者可能会编写出五花八门的数据库连接池,这对于代码后期的维护和使用会有非常多的问题,为了能够统一数据库连接池的编写规范,让开发者编写出统一标准的数据库连接池,sun公司提供了一个规范,该规范其实就是一个位于javax.sql包下的DataSource的接口,也叫作数据源,如果要想自己编写数据库连接池,那么需要去实现该接口,有了这个标准之后,我们只要是看到了一个类实现了该接口,那就说明这个类是一个数据库连接池,该接口提供了两个重载的getConnection方法:

Connection getConnection() throws SQLException;
Connection getConnection(String username, String password) throws SQLException;

创建MyPool类去实现DataSource接口,这样就创建好了一个符合规范的数据库连接池。

package com.monkey1024.jdbc.pool;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.logging.Logger;

import javax.sql.DataSource;

import com.monkey1024.jdbc.util.DBUtil;

/**
 * 数据库连接池规范
 *
 */
public class MyPool implements DataSource {

    // 创建一个存放连接的池子
    private static LinkedList<Connection> pool = (LinkedList<Connection>) Collections
            .synchronizedList(new LinkedList<Connection>());

    static {
        try {
            for (int i = 0; i < 10; i++) {
                Connection conn = DBUtil.getConnection();
                pool.add(conn);
            }
        } catch (Exception e) {
            throw new ExceptionInInitializerError("初始化数据库连接失败,请检查配置文件是否正确!");
        }
    }

    public Connection getConnection() throws SQLException {
        Connection conn = null;
        if (pool.size() > 0) {
            //将连接池中的一个连接取出
            conn = pool.removeFirst();
            return conn;
        } else {
            // 此时说明连接池中已经没有空闲连接了,需要等待
            throw new RuntimeException("服务器忙。。。");
        }
    }

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

    @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;
    }

}

编写数据库连接池测试类伪代码:

package com.monkey1024.jdbc.pool;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.sql.DataSource;

/**
 * 数据库连接池测试类
 *
 */
public class PoolTest {

    public static void main(String[] args) {
        DataSource ds = new MyPool();
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = ds.getConnection();
            //里面的sql语句省略
            ps = conn.prepareStatement("....");

        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            try {
                //这个地方不能关闭,用完之后需要再重新放入到池中
                conn.close();

            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

}

需要注意的地方就是当数据库连接使用完毕之后,不能直接关闭该连接,而是需要重新放入到池中,也就是说数据库连接的创建和关闭全部交给数据库连接池来管理,程序在需要的时候直接从池中获取,使用完毕后再归还给池。上面代码有个问题,就是在DataSource接口中并没有定义将连接放回到池中的方法,那我们该如何将连接放回到池中?这里可以使用装饰者设计模式来解决这个问题。