数据库连接池

前述:

  对之前JDBC的操作,不管是原始的操作步骤,还是JDBCUtils工具类的写法,都存在一个严重的问题:每次我们都需要去创建一个连接对象,然后再释放掉资源的操作。

  从效率和内存的角度,这种重复创建和释放的操作方式是不可取的。那么该如何优化?

  既然知道了问题是出现在重复创建和释放的操作上,那我们便可以对症下药--让重复不再重复。

  于是,结合线程池的思想,我们也可以创建一个容器来存放一定数量的数据库连接对象,在使用时获取,在关闭时归还。---我们称之为数据库连接池

一、数据库连接池

 1.1 概述

    存放数据库连接的容器(集合)。

    作用:高效率,节约资源。

 1.2 代码实现

    接口标准:javax.sql.DataSource

    • 获取连接:getConnection()
    • 归还连接:Connection.close()。  // 如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了,而是归还连接。

 小贴士:一般我们不去实现它,由数据库厂商来实现,比如:

  • C3P0:数据库连接池技术
  • Druid:数据库连接池实现技术(由阿里巴巴提供的)

二、C3P0 数据库连接池技术

 2.1 步骤

    1. 导入jar包 (两个: c3p0-0.9.5.2.jar、mchange-commons-java-0.2.12.jar)
    2. 定义配置文件:
      * 名称:c3p0.properties 或者 c3p0-config.xml
      * 路径:直接将文件放在src目录下即可。
    3. 创建核心对象:数据库连接池对象 ComboPooledDataSource
    4. 获取连接:getConnection

 2.2 代码实现

    1. 创建数据库连接池对象
    DataSource ds  = new ComboPooledDataSource();
    2. 获取连接对象
    Connection conn = ds.getConnection();

三、Druid 数据库连接池实现技术(由阿里巴巴提供)

 3.1 步骤

    1. 导入jar包 druid-1.0.9.jar
    2. 定义配置文件:
      * 是properties形式的,如druid.properties
      * 可以叫任意名称,可以放在任意目录下
    3. 加载配置文件。Properties
    4. 获取数据库连接池对象:通过工厂类来获取 DruidDataSourceFactory
    5. 获取连接:getConnection

 3.2 代码实现

    1.加载配置文件
    Properties pro = new Properties();
    InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
    pro.load(is);
    2.获取连接池对象
    DataSource ds = DruidDataSourceFactory.createDataSource(pro);
    3.获取连接对象
    Connection conn = ds.getConnection();

四、重新定义JDBCUtils工具类

 4.1 步骤

    1. 定义一个工具类 JDBCUtils
    2. 提供静态代码块加载配置文件,初始化连接池对象
    3. 提供方法
      *  获取连接方法:通过数据库连接池获取连接
      *  释放资源
      *  获取连接池的方法

 4.2 代码实现(使用Druid连接池)

public class JDBCUtils {

	//1.定义成员变量 DataSource
	private static DataSource ds ;

	static{
		try {
			//1.加载配置文件
			Properties pro = new Properties();
			pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
			//2.获取DataSource
			ds = DruidDataSourceFactory.createDataSource(pro);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取连接
	 */
	public static Connection getConnection() throws SQLException {
		return ds.getConnection();
	}

	/**
	 * 释放资源
	 */
	public static void close(Statement stmt,Connection conn){
	   /* if(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(conn != null){
			try {
				conn.close();	//归还连接
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}*/

	   close(null,stmt,conn);
	}
	/**
	 * 释放资源
	 */
	public static void close(ResultSet rs , Statement stmt, Connection conn){
		if(rs != null){
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(conn != null){
			try {
				conn.close();	//归还连接
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 获取连接池方法
	 */
	public static DataSource getDataSource(){
		return ds;
	}
			
}

  

五、Spring JDBC

 5.1 概述

    Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发。

 5.2 步骤

    1. 导入相关的jar包;(如:spring-jdbc-5.0.0.RELEASE.jar等)
    2. 创建JdbcTemplate对象。依赖于数据源DataSource
      * JdbcTemplate template = new JdbcTemplate(ds);
    3. 调用JdbcTemplate的方法来完成CRUD的操作
      * update():执行DML(增、删、改)语句。
      * queryForMap():查询结果将结果集封装为map集合。
        * 注意:查询的结果集长度只能是1,将列名作为key,将值作为value, 将这条记录封装为一个map集合。
      * queryForList():查询结果将结果集封装为list集合。
        * 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中。
      * query():查询结果,将结果封装为JavaBean对象。
      * query的参数:RowMapper
        * 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装。
        * new BeanPropertyRowMapper<类型>(类型.class)
      * queryForObject:查询结果,将结果封装为对象。
        * 一般用于聚合函数的查询


 面试题:数据库连接池的工作机制是什么?

  J2EE服务器启动时会建立一定数量的连接池,并一直维持不少于此数目的池连接。
  客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其标记为忙。
  如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量由配置参数决定。
  当使用的池连接调用完成后,池驱动程序将此连接标记为闲,其他调用就可以使用这个连接。
  实现方式,返回的Connection是原始Connection的代理,代理Connection的close方法不是真正关闭连接,而是把它代理的Connection对象还回到连接池中。

原文地址:https://www.cnblogs.com/sun9/p/13599394.html