JDBC 数据库连接池

基本概念

先看一张普通连接数据库图:

  多个用户操作数据库,向数据库获得链接。数据库创建连接需要较大的资源,而且创建时间长,假设一个网站一天有超10万的访问量,则数据库就需要创建更多的连接,这样极大的浪费资源,而且很容易造成数据库服务器内存溢出、拓机。

如何解决此类问题,出现了数据库连接池。如图所示:

  连接池相当于一个容器(集合),存放数据库连接的容器。当系统初始化好了以后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,当用户访问完,会将连接对象归还给容器。

详细点就是:

  使用连接对象之前先创建好规定数量(根据服务器内存的承载能力制定)的连接对象存到放连接池(实现池子的方式一般是用链表结构的集合来实现)中,当应用服务器需要连接对象的时候就从连接池中获取,用完该连接对象时归还连接对象到连接池中。当应用服务器需要连接对象而当前池子中没有连接对象可取时,就让其先等待,如果等待超时还没有回获取到连接对象,就新建一个连接对象给服务器让其使用,用完后销毁该创建的对象。

我的理解

  就是,当你需要获取数据库连接时,你只需要创建一个连接池对象,定义好sql语句,给到连接池,就可以操作数据库。连接池对象就是个工具类,我们需要使用它就创建其对象,写好SQL语句就可实现操作数据库。数据库连接池中已经定义好了连接信息,而且我们可以通过修改其配置文件,实现不同数据之间的访问,也可以自定义最大连接量。

数据库连接池的好处

  1. 节约资源(不是关闭连接而是归还)
  2. 用户访问高效(直接获取连接对象,不用创建)

一个最基本的连接池:

public class PersonalConnectionPool {

    /**
     * 用户名
     */
    private static String user;
    /**
     * 密码
     */
    private static String password;
    /**
     * 连接数据库的URL
     */
    private static String url;


    /**
     * 连接池
     * 规定最大连接数为3
     */
    private static LinkedList<Connection> pool;

    /**
     * 从属性文件中加载数据库驱动,初始化连接池
     */
    static{
        try {
            Properties properties = new Properties();
            pool = new LinkedList<Connection>();
            Class.forName("com.mysql.jdbc.Driver");
            ClassLoader classLoader = PersonalConnectionPool.class.getClassLoader();
            InputStream iStream = classLoader.getResourceAsStream("mysqlCongfig.properties");
            properties.load(iStream);
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            //创建三个连接对象(包装类对象)放到池子中
            for (int i = 0; i < 3; i++) {
                Connection connection = DriverManager.getConnection(url, user, password);
                Connection connectionWrapper = new ConnectionWapper(connection,pool);
                pool.add(connectionWrapper);
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


    /**
     * @throws SQLException 
     * @method 向外提供连接对象
     */
    public Connection getConnection() throws SQLException {

        Connection connection;
        if(pool.size()>0)
        {
            connection = pool.removeFirst();
        }
        else
        {
            //等待超时,返回一个新创建的对象
            connection = DriverManager.getConnection(url, user, password);
        }
        System.out.println("当前池子中有  "+pool.size()+" 个对象");
        return connection;
    }

    /**
     * 归还连接对象
     * 直接简化在包装类的close方法中
     */
}


池子中用了到了一个包装类,包装了通过DriverManager.getConnection获取到的Connection的实现类对象,该包装也实现了Connection接口,重写了案例中需要的方法。该类结构如下:
public class ConnectionWapper implements Connection {

    /**
     * Connection接口的实现类对象的引用
     */
    private Connection connection;
    /**
     * 存放连接包装对象的池子的引用
     * 
     */
    private LinkedList<Connection> pool;
    /**
     * 
     * @param connection 的实现类对象
     */
    public ConnectionWapper(Connection connection, LinkedList<Connection> pool) {
        super();
        this.connection = connection;
        this.pool = pool;
    }
    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        PreparedStatement prepareStatement = connection.prepareStatement(sql);
        return prepareStatement;
    }
    @Override
    public void close() throws SQLException {

        pool.add(this);
        System.out.println("当前池子中有  "+pool.size()+" 个对象");

    }

    @Override
    ...
}

基于统一,JAVA为数据库连接池提供了公共接口,要求所有项目开发的连接池必须实现DataSource接口,可一统一用一套接口的方法使用不同开发商的数据库连接池。

常用连接池

dbcp连接池

  • 封装dbcp连接池创建一个数据库工具类
/**
 * (封装dbcp连接池来创建数据库工具类)
 * (属性文件为源文件夹properties下的dbcpconfig.properties)
 */
public class DatabaseUtil {

    /**
     * 数据库连接池(dbcp连接池)对象引用
     */
    private static DataSource dbcpPoor;

    /**
     * 只执行一次
     */
    static {
        Properties properties = new Properties();
        ClassLoader classLoader = DatabaseUtil.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("dbcpconfig.properties");
        try {
            properties.load(resourceAsStream);
            //通过直接创建连接池对象并设置参数方法创建连接池对象
//          BasicDataSource basicDataSource = new BasicDataSource();
//          basicDataSource.setUsername(properties.getProperty("username"));
//          basicDataSource.setPassword(properties.getProperty("password"));
//          basicDataSource.setDriverClassName(properties.getProperty("driverClassName"));
//          basicDataSource.setUrl(properties.getProperty("url"));
//          
//          dbcpPoor = basicDataSource;
            //通过工厂的方法创建连接池对象
            dbcpPoor = BasicDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 获取连接对象
     * @throws SQLException 
     */
    public static Connection getConnection() throws SQLException{
        Connection connection = dbcpPoor.getConnection();
        System.out.println("获取连接对象成功");
        return connection;
    }

    /**
     * 关闭资源
     */
    //关闭建立的连接对象,释放资源
        public static void closeSourceConnection(Connection connection, Statement statement, ResultSet resultSet){

            try {
                if (connection!=null) {
                    connection.close();
                }
                if (statement!=null) {
                    statement.close();
                }
                if (resultSet!=null) {
                    resultSet.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        public static DataSource getDbcpPoor() {
        return dbcpPoor;
    }
}

c3p0连接池

  • 封装c3p0连接池创建一个数据库工具类
/**
 * (封装c3p0连接池来创建数据库工具类)
 * @author YanoHao
 *
 */
public class DatabaseUtil {
    /**
     * c3p0连接池对象的引用
     */
    private static DataSource c3p0Poor;
    /**
     * 创建一次
     */
    static {
        //直接创建连接池对象(自动加载配置文件,无需设置参数)
        c3p0Poor = new ComboPooledDataSource();
        //通过工厂的方式创建连接池对象
        //      try {
//          DataSource unpooledDataSource = DataSources.unpooledDataSource();
//          c3p0Poor = DataSources.pooledDataSource(unpooledDataSource);
//      } catch (SQLException e) {
//          // TODO Auto-generated catch block
//          e.printStackTrace();
//      }
    }
    /**
     * 获取连接对象
     * @throws SQLException 
     */
    public static Connection getConnection() throws SQLException{

        Connection connection = c3p0Poor.getConnection();
        System.out.println("获取连接对象成功");
        return connection;
    }

    /**
     * 关闭资源
     */
    //关闭建立的连接对象,释放资源
        public static void closeSourceConnection(Connection connection, Statement statement, ResultSet resultSet){

            try {
                if (connection!=null) {
                    connection.close();
                }
                if (statement!=null) {
                    statement.close();
                }
                if (resultSet!=null) {
                    resultSet.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        public static DataSource getC3p0Poor() {
            return c3p0Poor;
        }
}

druid连接池

  • 封装druid连接池创建一个数据库工具类
/*
 * 封装druid连接池创建工具类
 */
public class DatabaseUtil {

    /**
     * 数据库连接池(druid连接池)对象引用
     */
    private static DataSource druidPool;

    static {
        try {
            Properties properties = new Properties();
            ClassLoader classLoader = DatabaseUtil.class.getClassLoader();
            InputStream resourceAsStream = classLoader.getResourceAsStream("druidconfig.properties");
            properties.load(resourceAsStream);
            //通过直接创建连接池对象的方式创建连接池对象
//          DruidDataSource druidDataSource = new DruidDataSource();
//          druidDataSource.setUsername(properties.getProperty("username"));
//          druidDataSource.setPassword(properties.getProperty("password"));
//          druidDataSource.setUrl(properties.getProperty("url"));
//          druidDataSource.setDriverClassName(properties.getProperty("driverClassName"));
//          druidPool = druidDataSource;
            //通过工厂的方式创建连接池对象
            druidPool = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
    }

    public static Connection getConnection() throws SQLException{

        Connection connection = druidPool.getConnection();
        return connection;
    }

    /**
     * 
     * 关闭建立的连接对象,释放资源
     */
    public static void closeSourceConnection(Connection connection, Statement statement, ResultSet resultSet){

        try {
            if (connection!=null) {
                connection.close();
            }
            if (statement!=null) {
                statement.close();
            }
            if (resultSet!=null) {
                resultSet.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static DataSource getDruidPool() {
        return druidPool;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值