数据库连接池

原创 2016年08月29日 11:56:24

数据库连接池

     数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
     连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用 户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控 制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等。也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。

——参考《百度百科》

为什么需要连接池

     通过下图可以看出,数据库建立连接的操作是一个很耗费时间的过程。如果每一次SQL操作都新开一个连接执行的话,那么其耗时是非常严重的,那么在追求实时性的系统中,这样的延迟肯定是不允许的。这时候就能通过连接池,进行预分配连接,每当用户使用完毕,再将连接放回连接池即可。


连接池模型



Java连接池的一些种类


参考:java项目几种常见数据库连接池的使用比较
参考:Java数据库连接池比较

DBCP连接池

DBCP(DataBase connection pool)数据库连接池。是Apache上的一个java连接池项目,也是tomcat使用的连接池组件。单独使用dbcp需要3个包:commons-dbcp.jar,commons-pool.jar,commons-collections.jar

BasicDataSource对象

     通过BasicDataSource对象可以配置JDBC连接池的DriverName,URL,User和Password。
public static void dbpoolInit() {
    dataSource = new BasicDataSource();
    dataSource.setDriverClassName(DRIVER_NAME);
    dataSource.setUrl(DB_URL);
    dataSource.setUsername(USER);
    dataSource.setPassword(PASSWORD);
}

     设置完这些属性之后,可以通过getConnection()方法,获取一个连接。
public static void dbPoolTest() {
    try {
        ct = dataSource.getConnection();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

     接下来的操作就和JDBC的基本操作一样的了。

public static void dbPoolTest() {
    try {
        ct = dataSource.getConnection();
        String sql = "select * from user";
        ps = ct.prepareStatement(sql);
        rs = ps.executeQuery();
        while(rs.next()) {
            System.out.println(rs.getString("userName"));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        try {
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
            if (ct != null) {
                ct.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

PS:DBCP重写了Connection接口的close()方法,所以调用close()方法的逻辑由关闭连接,清理环境变成了将该连接归还给连接池中。也可以不做关闭操作,因为该操作已经由连接池接管。建议不关闭。

使用属性文件配置DBCP线程池

  1. 配置dbcpconfig.properties配置文件

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=123456
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=REPEATABLE_READ

  1. 工具类

package com.pc.jdbc.dbcp.utils;
/**
 * 基于DBCP的工具类,提供数据库源和连接
 * @author Switch
 * @data 2016年9月30日
 * @version V1.0
 */

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

public class DBCPUtils {
   // 数据源
   private static DataSource dataSource = null;

   // 静态块初始化数据源
   static {
      try {
         // 获取文件流
         InputStream is = DBCPUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
         // 创建Properties对象
         Properties props = new Properties();
         // 加载文件流
         props.load(is);
         dataSource = BasicDataSourceFactory.createDataSource(props);
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   /**
    * 返回连接
    * @return
    */
   public static Connection getConnection() {
      Connection ct = null;
      try {
         ct = dataSource.getConnection();
      } catch (SQLException e) {
         e.printStackTrace();
      }
      return ct;
   }

   /**
    * 返回数据源
    * @return
    */
   public static DataSource getDataSource() {
      return dataSource;
   }

}

  1. 测试类

package com.pc.jdbc.dbcp.test;

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

import org.junit.Test;

import com.pc.jdbc.dbcp.utils.DBCPUtils;

/**
 * 测试DBCP
 *
 * @author Switch
 * @data 2016年9月30日
 * @version V1.0
 */
public class TestDBCP {
   @Test
   public void test_get_connection() {
      Connection ct = DBCPUtils.getConnection();
      PreparedStatement pstmt = null;
      ResultSet rs = null;
      try {
         String sql = "select * from users";
         pstmt = ct.prepareStatement(sql);
         rs = pstmt.executeQuery();
         while (rs.next()) {
            System.out.println(rs.getInt("id") + " " + rs.getString("username") + " " + rs.getString("password"));
         }
      } catch (SQLException e) {
         e.printStackTrace();
      }
   }
}


高级配置


连接数管理

InitialSize:初始化的连接数量(设置为预期业务平均访问量比较合适)
MaxActive:设置连接池连接数的最大激活连接数,起到限流保护数据库的作用(能够使用的最大连接数,请求数超过该数,超过的请求会进入等待队列中)
MaxWaitMillis:设置当请求连接数超过连接池最大激活连接数之后,等待请求的最大等待时间。(超过会抛出SQLException异常)
MaxIdle:设置最大空闲连接数(空闲连接数超过该值,则会自动释放连接,直到小于等于它)
MinIdle:设置最小空闲连接数(空闲连接数小于该值,则会自动创建连接,直到大于等于它)(为了避免连接池频繁的释放、创建连接,一般将MaxIdle和MinIdle设置为相同值)
dataSource.setInitialSize(5);
dataSource.setMaxActive(20);
dataSource.setMaxWait(100000);
dataSource.setMaxIdle(2);
dataSource.setMinIdle(2);

定期检测

TestWhileIdle:定期检测连接池中的连接是否有效,设置为true开启该功能(比如说MySQL数据库,8个小时未访问,则服务器端自动关闭该连接,这时客户端连接池并不知道服务器关闭了该连接,所以超过了就会抛出SQLException异常,可以通过设置这个功能,来避免发生这种情况)
MinEvictableIdleTimeMillis:连接池的闲置连接,最小的空闲时间,当超过该值时,则该连接会被连接池销毁,并会补充新的连接(该值一定要小于DBMS预置的连接空闲关闭时间)
TimeBetweenEvictionRunsMillis:连接池空闲连接清理线程的运行时间间隔。The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread will be run.
dataSource.setTestWhileIdle(true);
dataSource.setMinEvictableIdleTimeMillis(7 * 3600 * 1000);
dataSource.setTimeBetweenEvictionRunsMillis(3600 * 1000 - 5);

C3P0连接池

常见配置项



分类
属性
描述

user 
用户名
必须项
password
密码

driverClass
 驱动mysql 驱动,com.mysql.jdbc.Driver

jdbcUrl
路径,mysql路径,jdbc:mysql://localhost:3306/数据库


acquirelncrement
连接池无空闲连接可用时,一次性创建的新连接数
默认值: 3
基本配置
initialPoolSize
连接池初始化时创建的连接数
默认值: 3

maxPoolSize
连接池中拥有的最大连接数
默认值: 15

minPoolSize
连接池保持的最小连接数。

maxldleTime
连接的最大空闲时间。如果超过这个时间,某个数据库连接还没有被使用,则会断开掉这个连接,如果为0.则永远不会断开连接。
默认值: 0

管理连接池的大小和连接的生存时间(扩展)
maxConnectionAge
配置连接的生存时间,超过这个时间的连接将由连接池自动断开丢弃掉。当然正在使用的连接不会马上断开,而是等待它close再断开。配置为0的时候则不会对连接的生存时间进行限
制。默认值0

maxldleTimeExcessConnections
这个配置主要是为了减轻连接池的负载,配置不为0, 则会将连接池中的连接数量保持到minPoolSize, 为0则不处理。

配置 Prepared Statement缓存(扩展)
maxStatements
连接池为数据源缓存的PreparedStatement的总数。由于PreparedStatement属于单 个Connection, 所以这个数量应该根据应用中 平连接数乘以每个 连接的平均PreparedStatement来计算 。为 0 的 时 候 不 缓存,同时 maxStatementsPerConnection的配置无效。

maxStatementsPerConnection
连接池为数据 源单个 Connection 缓存的PreparedStatement数 , 这个配置maxStatements更有意义,因为它缓存的服务对象是单个数据连接, 如果设置的好, 肯定是可以提高性能的。 为0的时候不缓存。

硬编码配置

package com.pc.jdbc;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Created by switch on 16/8/29.
 */
public class JDBC5 {
    public final static String DRIVER_NAME = "com.mysql.jdbc.Driver";
    public final static String DB_URL = "jdbc:mysql://localhost:3306/cloud_study";
    public final static String USER = "root";
    public final static String PASSWORD = "123456";

    private static Connection ct = null;
    private static PreparedStatement ps = null;
    private static ResultSet rs = null;

    private static ComboPooledDataSource dataSource = null;

    private static void dbPoolInit() {
        try {
            dataSource = new ComboPooledDataSource();
            // 设置基本信息
            dataSource.setDriverClass(DRIVER_NAME);
            dataSource.setJdbcUrl(DB_URL);
            dataSource.setUser(USER);
            dataSource.setPassword(PASSWORD);

            // 设置初始化连接数量
            dataSource.setInitialPoolSize(10);
            // 设置最大连接数量
            dataSource.setMaxPoolSize(20);
            // 设置最小连接数量
            dataSource.setMinPoolSize(5);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
    }

    private static void dbPoolTest() {
        try {
            ct = dataSource.getConnection();
            String sql = "select * from user";
            ps = ct.prepareStatement(sql);
            rs = ps.executeQuery();
            while (rs.next()) {
                System.out.println(rs.getString("userName"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (ps != null) {
                    ps.close();
                }
                if (ct != null) {
                    ct.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        dbPoolInit();
        dbPoolTest();
    }

}



XML文件配置

  1. 配置c3p0-config.xml配置文件

<?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/test?useUnicode=true&characterEncoding=utf8</property>
      <property name="user">root</property>
      <property name="password">123456</property>
      <!-- 连接数配置信息 -->
      <property name="initialPoolSize">5</property>
      <property name="maxPoolSize">20</property>
   </default-config>

   <!-- 按名指定配置信息 -->
   <named-config name="mysql2">
      <property name="driverClass">com.mysql.jdbc.Driver</property>
      <property name="jdbcUrl">jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf8</property>
      <property name="user">root</property>
      <property name="password">123456</property>
   </named-config>

</c3p0-config>


  1. 工具类

package com.pc.jdbc.c3p0.utils;
/**
 * 基于C3P0的工具类,提供数据库源和连接
 * @author Switch
 * @data 2016年9月30日
 * @version V1.0
 */

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

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Utils {
   // 使用c3p0-config.xml中的默认配置
   private static DataSource dataSource = new ComboPooledDataSource();

   /**
    * 获取数据源
    * @return
    */
   public static DataSource getDataSource() {
      return dataSource;
   }

   /**
    * 获取连接
    * @return
    */
   public static Connection getConnection() {
      Connection ct = null;
      try {
         ct = dataSource.getConnection();
      } catch (SQLException e) {
         e.printStackTrace();
      }
      return ct;
   }
}

  1. 测试类

package com.pc.jdbc.c3p0.test;

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

import org.junit.Test;

import com.pc.jdbc.c3p0.utils.C3P0Utils;

public class TestC3P0 {

	@Test
	public void test_c3p0_getConnection() {
		Connection ct = C3P0Utils.getConnection();
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			String sql = "select * from users";
			pstmt = ct.prepareStatement(sql);
			rs = pstmt.executeQuery();
			while (rs.next()) {
				System.out.println(rs.getInt("id") + " " + rs.getString("username") + " " + rs.getString("password"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

PS:附上GitHub地址https://github.com/Switch-vov/the-example-datasource



-------------参考《网易云课堂.数据库开发》


版权声明:如需转载,请联系本人获取许可且必须注明出处,详见联系方式。 举报

相关文章推荐

返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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