JDBC连接数据库(三):连接池

连接池概述

一. 为什么要用连接池技术

  传统数据库访问方式:一次数据库访问对应一个物理连接,每次操作数据库都要打开、关闭该物理连接, 系统性能严重受损。

解决办法:数据库连接池技术。

  系统初始运行时,主动建立足够的连接,组成一个池.每次应用程序请求数据库连接时,无需重新打开连接,而是从池中取出已有的连接,使用完后,不再关闭,而是归还。

二. 连接池的组成

  1. 连接池的建立;
  2. 连接池中连接的使用管理;
  3. 连接池的关闭。

三. 连接池的核心思想

   连接复用。通过建立一个数据库连接池以及一套连接使用、分配、管理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。

1. 连接池的建立

  在系统初始化时,根据相应的配置,创建连接并放置在连接池中,以便需要使用时能从连接池中获取。可以避免连接随意的建立、关闭造成的开销。

2. 连接池中连接的使用管理

  采用的方法是:Reference Counting(引用记数)。该模式在复用资源方面应用的非常广泛,把该方法运用到对于连接的分配释放上,为每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。

  • (1)当客户请求数据库连接时,首先查看连接池中是否有空闲连接(指当前没有分配出去的连接)。如果存在空闲连接,则把连接分配给客户并作相应处理(即标记该连接为正在使用,引用计数加1)。如果没有空闲连接,则查看当前所开的连接数是不是已经达到maxConn(最大连接数),如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的maxWaitTime(最大等待时间)进行等待,如果等待maxWaitTime后仍没有空闲连接,就抛出无空闲连接的异常给用户。

  • (2)当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就删除该连接,并判断当前连接池内总的连接数是否小于minConn(最小连接数),若小于就将连接池充满;如果没超过就将该连接标记为开放状态,可供再次复用。

好处:保证了数据库连接的有效复用,避免频繁地建立、释放连接所带来的系统资源开销。

3. 连接池的关闭

   当应用程序退出时,关闭连接池,把在连接池建立时向数据库申请的连接对象统一归还给数据库(即关闭所有数据库连接)。


几大主流连接池的使用

一. dbcp(Database Connection Pool)

(一)dbcp连接池的相关认识

  DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。

(二)所需jar包

在这里插入图片描述

(三)重要参数

1. 连接配置

在这里插入图片描述

2. 提交属性

在这里插入图片描述
在这里插入图片描述

3. 连接属性

在这里插入图片描述

注意针对负载比较高的应用,最好设置maxIdle接近于maxTotal,例如设置的数量为maxTotal-1甚至等于maxTotal,或者无限制。

(四)两种方式得到数据源

方式一:

配置文件:dbcp.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/stuinformation?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
initialSize=5
maxTotal=10

工具实现类

public class JdbcUtils {
    // 定义BasicDataSorce的父类接口的形式,获得ds的参数
    private static BasicDataSource ds;
    static {
        try {
            //创建一个properties容器
            Properties pro = new Properties();
            //使用类加载器获取properties文件内容的流对象
            InputStream stream = JdbcUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");
            //加载字节输入流
            pro.load(stream);
            //关闭流
            stream.close();
             
            //创建BasicDataSource对象
            ds = new BasicDataSource();
            ds.setDriverClassName(pro.getProperty("jdbc.driverClassName"));
            ds.setUrl(pro.getProperty("jdbc.url"));
            ds.setUsername(pro.getProperty("jdbc.username"));
            ds.setPassword(pro.getProperty("jdbc.password"));
            ds.setInitialSize(Integer.parseInt(pro.getProperty("initialSize")));
            ds.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获得数据库连接对象
    public static BasicDataSource getDataSource() {
        return ds;
    }
    // 获得与指定数据库的连接
    public static Connection getConnection(){
        Connection conn = null;
        try{
            conn = ds.getConnection();
        }catch(Exception e){
            e.printStackTrace();
        }
        return conn;
    }
}

注意dbcp.properties文件中的key与资源文件中的参数不一致,则需要先创建一个数据源BasicDataSource ds = new BasicDataSource();,然后给相应的属性赋setXXX。

方式二:

配置文件:db.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/stuinformation?characterEncoding=utf-8
username=root
password=root
initsize=1 
maxtotal=10
maxwait=5000
maxidle=10
minidle=1

工具实现类

import java.sql.Connection;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
/*
 *对应的配置文件是:db.properties
 *
 * 使用DBCP连接池技术管理数据库连接
*/
 
public class DBCPUtil {
    //数据库连接池
    private static DataSource dbcp;
    //为不同线程管理连接
    private static ThreadLocal<Connection> th1;
    //通过配置文件来获取数据库参数
    static{
        try{
            Properties pro = new Properties();
            InputStream stream = DBCPUtil.class.getClassLoader().getResourceAsStream("db.properties");
            //加载字节输入流
            pro.load(stream);
            //关闭流
            stream.close(); 

            //1.初始化连接池
            //BasicDataSource 是dbcp的核心连接池 BasicDataSource 实现了Datasource这个接口
            dbcp = BasicDataSourceFactory.createDataSource(pro);
            //初始化本地线程
            th1 = new ThreadLocal<Connection>();   
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

    /*获得数据库连接
     * @return
     * @SQLException
     * */
    public static Connection getConnection(){
        Connection conn=null;
        try{
            conn=dbcp.getConnection();
            th1.set(conn);
        }catch(Exception e){
            e.printStackTrace();
        }
        return conn;
    }

    /*
     * 关闭数据库连接
     * */
 
    public static void closeConn(){
        Connection conn = th1.get();
        try{
        if(conn!=null){    
             /* 
             *通过连接池获取Connection对象,然后调用close方法,实际上并没有将连接关闭,而是归还
             * 了Connection连接对象
             * */
              
            conn.close();
            th1.remove();
        }
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

注意:db.properties文件中的key与资源文件中规定的名字一致,则可以使用DataSource dbcp = BasicData SourceFactory.createDataSource(Properties pro);的方式得到数据源。

重要:获取了Connection对象后,对于增删改查操作,正常的使用jdbc去写。!!


二. C3P0连接池

(一)C3P0连接池的相关认识

   是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring。

优点

1) 资源重用:避免了频繁创建,减少大量不必要的性能开销,增加了系统运行环境的平稳性。
 2)更快的系统反应速度:数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间。
 3)新的资源分配手段:对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源。
 4)统一的连接管理,避免数据库连接泄露:在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。      

(三)c3p0连接池的使用

   c3p0连接池jar下载地址: https://sourceforge.net/projects/c3p0/或:http://mvnrepository.com/中搜索。

需要使用的jar包:
在这里插入图片描述
c3p0工具类(使用xxx.properties文件)

注意:数据源的获取: new ComboPooledDataSource()

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3p0Utils {
	private static ComboPooledDataSource cpds = null;
	static {
		try {
			/* 加载配置文件 */
			Properties pro = new Properties();
			// 用类加载器的方式加载配置文件
			InputStream stream = C3p0Utils.class.getClassLoader().getResourceAsStream("c3p0.properties");
			// 将资源放入properties容器中
			pro.load(stream);
			stream.close();
			/* 创建数据源对象 */
			cpds = new ComboPooledDataSource();
			System.out.print(cpds);
			cpds.setDriverClass(pro.getProperty("/c3p0.driverClass"));
			cpds.setJdbcUrl(pro.getProperty("c3p0.jdbcUrl"));
			cpds.setUser(pro.getProperty("c3p0.user"));
			cpds.setPassword(pro.getProperty("c3p0.password"));
		} catch (IOException | PropertyVetoException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/* 获取Connection连接对象 */
	public static Connection getConn() throws SQLException {
		return cpds.getConnection();
	}
}

三. Druid连接池

(一)Druid连接池的相关认识

  DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOO等DB池的 优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。

(二)Druid连接池的使用

  • 1.导入jar包 druid-1.1.10.jar

  • 2.定义配置文件 druid.properties 。名字可以任意,位置可以任意,通常在src下

  • 3.加载配置文件

  • 4.使用DruidDataSourceFactory的createDataSource获得连接池对象

  • 5.创建connection对象

  • 6.创建要执行的sql语句

  • 7.创建Statement/PreparedStatement对象执行sql语句

  • 8.获得ResultSet结果集对象(查询)或者返回影响的行数

  • 9.关闭连接,释放资源

(三)工具类的创建

  • 1.使用静态代码块加载配置文件

  • 2.使用DruidDataSourceFactory获得DataSource对象

  • 3.创建static方法返回Connection对象

  • 4.创建static方法返回DataSouce对象

  • 5.关闭连接

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

import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mysql.jdbc.PreparedStatement;

/*druid连接池的使用*/
public class DruidUtils {
  //数据源对象
  private static DataSource ds;
  //connection连接对象
  private static Connection conn;
  
  static{
  	
  	try {
  		
  	/*加载配置文件*/
  	Properties pro = new Properties();
  	InputStream stream = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
  	pro.load(stream);
  	/*获得数据库连接池对象*/
  	ds = DruidDataSourceFactory.createDataSource(pro);
  	} catch (Exception e) {
  	
  		e.printStackTrace();
  	}
  	
  }
  
  /*获取连接对象*/
  public static Connection getConn() throws Exception {
  	return ds.getConnection();
  }
  
  /*关闭连接,释放资源*/
  public static void close(Connection conn,PreparedStatement ps,ResultSet rs){
  	try{
  	if(rs!=null){
  		rs.close();
  	}
  	
  	if(ps!=null){
  		ps.close();
  	}
  	
  	if(conn!=null){
  		conn.close();
  	}
  	}catch (Exception e) {
  		e.printStackTrace();
  	}
  }

  /*获取连接池*/
  public static DataSource getDaSource(){
  	return ds;
  }
}

(四)xxx.properties配置文件

1. 数据源信息
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/stuinformation?characterEncoding=utf-8
username=root
password=root

#初始化连接数
initialSize=1

最大连接数

maxActive=10

最小连接数

minIdle=1

最大等待时间(毫秒)

maxWait=3000

已被取出的连接超过时间限制是否回收

removeAbandoned=true

已被取出的连接超过此时间限制未被利用会被回收的秒数

removeAbandonedTimeout=180

Destory线程会检测连接的间隔时间(毫秒)

timeBetweenEvictionRunsMillis=3000

连接池中未被取出的连接超过此时间限制会被关闭(毫秒)

minEvictableIdleTimeMillis=4000

用作测试的sql语句,用于检测连接是否可以

validationQuery=SELECT 1

申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测

testWhileIdle=true

申请连接时执行validationQuery检测连接是否有效,会降低性能

testOnBorrow=false

归还连接时执行validationQuery检测连接是否有效,会降低性能

testOnReturn=false

是否缓存预编译sql语句

poolPreparedStatements=false

缓存预编译sql语句的最大数量

maxPoolPreparedStatementPerConnectionSize=100

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值