数据库连接池(Druid、DBCP、C3P0)和Apache组织DBUtils工具类使用

本文详细介绍了数据库连接池的使用,包括自定义连接池、DBCP、C3P0和Druid的配置及应用。同时,讲解了Apache组织的DBUtils工具类在数据库操作中的简化作用,结合Druid连接池进行了封装实践。
摘要由CSDN通过智能技术生成

数据库连接池(Druid、DBCP、C3P0)和Apache组织DBUtils工具类使用

第一节:自定义连接池

使用JDBC操作数据库,需要建立Connection,使用传统的JDBC操作需要每次创建Connection,创建Connection是一个非常性能和消耗时间的过程,我们需要在提高程序性能,那么就需要减少每次创建创建连接带来的负面影响,解决这个问题我们将利用池子概念,预先创建一些链接放入池子中,如果需要操作数据,不用创建新的Connection,只需要在池子中获取即可,使用完毕放入池子!这样就形成了复用!

1.1自定义连接池

我们可以通过自定义的方式实现连接池!分析连接池类应该包含特定的属性和方法!

属性: 集合 放置Connection

方法: 获取连接方法

回收连接方法

具体实现代码:

public class Pool{ 
    static LinkedList<Connection> list = new LinkedList<Connection>(); 
    //初始化10个连接对象
    static{ 
        for (int i = 0; i < 10; i++) { 
            Connection connection = JDBCUtils.newInstance().getConnection(); 
            list.add(connection);
        }
    }
    /**
       * 从连接池子中获取连接的方式 
       * @return 
     */
    public static Connection getConnection(){ 
        //如果10个连接对象都在使用中,则list为空,自己再创建一个
        if (list.isEmpty()) { 
            Connection connection = JDBCUtils.newInstance().getConnection();
            list.addLast(connection);
        }
        //使用移除
        Connection conn = list.removeFirst(); 
        return conn; 
    }
    /**
       * 返回到连接池子中 
       */ 
    public static void addBack(Connection conn){ 
        if (list.size() >= 10) { 
            try {
                conn.close();
            } catch (SQLException e) { 
                e.printStackTrace();
            } 
        }else{
            list.addLast(conn); 
            //10 
        } 
    }
    /**
      * 获取连接池子中连接数量的方法
      */
    public static int getSize(){
        return list.size();
    }
}
1.2通过实现java规范实现连接池

Java为连接池实现提供了一个规范(接口),规范的写法,我们需要实现DataSource接口!

public class MyDbPool implements DataSource{
	//创建集合 并且线程安全Collections.synchronizedList
	public static List<Connection>  connctions=Collections.synchronizedList(new LinkedList<Connection>()) ;
	
	static{
		try {
            //读取properties文件
			InputStream is=MyDbPool.class.getClassLoader().getResourceAsStream("database.properties");
			Properties properties=new Properties();
			properties.load(is);

			String driver=properties.getProperty("driver");
			String url=properties.getProperty("url");
			String user=properties.getProperty("user");
			String password=properties.getProperty("password");
			//1加载驱动
			Class.forName(driver);
			
			for(int i=0;i<5;i++){
				Connection connection=DriverManager.getConnection(url, user, password);
				connctions.add(connection);
				System.out.println(i+"....."+connection.hashCode());
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public Connection getConnection() throws SQLException {
		// TODO Auto-generated method stub
		Connection connection=connctions.remove(0);
		System.out.println("获取一个连接.."+connection.hashCode());
		System.out.println("池中还剩"+connctions.size());
		return connection;
	}
	/**
	 * 把连接再放入池中
	 * @param conn
	 */
	public void release(Connection conn){
		connctions.add(conn);
		System.out.println("放入了一个连接"+conn.hashCode());
		System.out.println("池中还剩"+connctions.size());
	}
	

	@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;
	}
}
第二节:使用DBCP连接池

DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。

2.1 DBCP连接池的使用
2.1.1 创建项目

创建JavaWeb项目

2.1.2 导入相应jar包

mysql-jdbc.jar

commons-dbcp.jar

commons-pool.jar

2.1.3 硬编码方式使用DBCP连接池

所谓的硬编码方式就是在代码中添加配置

@Test
public void testHard() throws SQLException{ 
    //TODO 硬编码 使用DBCP连接池子 
    BasicDataSource source = new BasicDataSource(); 
    //设置连接的信息
    source.setDriverClassName("com.mysql.jdbc.Driver"); 
    source.setUrl("jdbc:mysql://localhost:3306/day2"); 
    source.setUsername("root"); 
    source.setPassword("111"); 
    Connection connection = source.getConnection(); 
    String sql = "select * from student"; 
    Statement createStatement = connection.createStatement();
    ResultSet executeQuery = createStatement.executeQuery(sql);
    while (executeQuery.next()) { 
        System.out.println(executeQuery.getString(2));
    }
    connection.close(); 
    //回收 
}
2.1.4 软编码方式使用DBCP连接池

所谓的软编码,就是在项目中添加配置文件,这样就不需要每次代码中添加配合

  1. 项目中添加配置

文件名称: info.properties,(只要是.properties结尾的)

文件位置: src下

#连接设置
driverClassName=com.mysql.jdbc.Driver 
url=jdbc:mysql://localhost:3306/day2 
username=root 
password=111 
#<!-- 初始化连接 --> 
initialSize=10 
#最大连接数量 
maxActive=50 
#<!-- 最大空闲连接 --> 
maxIdle=20 
#<!-- 最小空闲连接 --> 
minIdle=5 
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> 
maxWait=6000
  1. 代码实现
@Test 
public void testSoft() throws Exception{ 
    //TODO DBCP软编码连接池子使用 
    BasicDataSourceFactory factory = new BasicDataSourceFactory(); 
    Properties properties = new Properties();
    //配置文件添加到properties对象中 javase 
    properties.load(new FileInputStream("src/info.properties")); 
    //生成连接池子 需要配置文件 
    DataSource source = factory.createDataSource(properties); 
    Connection connection = source.getConnection(); 
    String sql = "select * from student"; 
    Statement createStatement = connection.createStatement();
    ResultSet executeQuery = createStatement.executeQuery(sql); 
    while (executeQuery.next()) { 
        System.out.println(executeQuery.getString(2));
    }
    connection.close(); 
    //回收
}
第三节:使用C3P0连接池

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

c3p0与dbcp区别 
1. dbcp没有自动回收空闲连接的功能 
    c3p0有自动回收空闲连接功能 
2. dbcp需要手动设置配置文件 
    c3p0不需要手动设置
3.1使用步骤
3.1.1创建项目
3.1.2导入jar包

c3p0-0.9.1.2.jar

mysql-connector-java-5.0.8.jar

3.1.3添加配置文件

c3p0是在外部添加配置文件,工具直接进行应用,因为直接引用,所以要求固定的命名和文件位置

文件位置: src

文件命名:c3p0-confifig.xml/c3p0-confifig.properties

<c3p0-config> 
    <!-- 默认配置,如果没有指定则使用这个配置 --> 
    <default-config> 
        <!-- 基本配置 --> 
        <property name="driverClass">com.mysql.jdbc.Driver</property> 
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day2</property> 
        <property name="user">root</property> 
        <property name="password">111</property> 
        
        <!--扩展配置--> 
        <!-- 连接超过30秒报错-->
        <property name="checkoutTimeout">30000</property> 
        <!--30秒检查空闲连接 --> 
        <property name="idleConnectionTestPeriod">30</property> 
        <property name="initialPoolSize">10</property>
        <!-- 30秒不适用丢弃--> 
        <property name="maxIdleTime">30</property> 
        <property name="maxPoolSize">100</property> 
        <property name="minPoolSize">10</property> 
        <property name="maxStatements">200</property> 
    </default-config>
    
    <!-- 命名的配置 --> 
    <named-config name="zhaowf">
        <property name="driverClass">com.mysql.jdbc.Driver</property> 
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day</property> 
        <property name="user">root</property> 
        <property name="password">111</property>
        <!-- 如果池中数据连接不够时一次增长多少个 --> 
        <property name="acquireIncrement">5</property> 
        <property name="initialPoolSize">20</property> 
        <property name="minPoolSize">10</property>
        <property name="maxPoolSize">40</property>
        <property name="maxStatements">20</property> 
        <property name="maxStatementsPerConnection">5</property> 
    </named-config> 
</c3p0-config>

注意: c3p0的配置文件内部可以包含命名配置文件和默认配置文件!默认是选择默认配置!如果需要切换命名配置可以在创建c3p0连接池的时候填入命名即可!

3.2使用C3P0进行数据库操作
public class TestC3p0 { 
    public static void main(String[] args) throws Exception { 
        //1.创建C3P0连接池子
        Connection connection = DataSourceUtils.getConnection(); 
        Statement createStatement = connection.createStatement(); 
        String sql = "select * from student;"; 
        ResultSet resultSet = createStatement.executeQuery(sql);
        while (resultSet.next()) { 
            System.out.println(resultSet.getString(1)); 
        }
        DataSourceUtils.close(connection, createStatement, resultSet); 
    } 
}
3.3 使用C3P0连接池编写工具类
/*** 从连接池子中获取连接! 
  ** C3P0的连接池子 
   * 0.获取连接池子对象 DBUtils 
   * 1.获取连接 
   * 2.关闭资源 
   */ 
public class DataSourceUtils { 
    private static ComboPooledDataSource dataSource = new 
        ComboPooledDataSource(); 
    /**
      * 返回连接池对象方法 
      * @return c3p0连接池子
      */ 
    public static ComboPooledDataSource getDataSource(){ 
        return dataSource; 
    }
    /**
      * 连接池中获取连接的方法
      * @return 连接 
      */ 
    public static Connection getConnection(){
        Connection conn = null; 
        try { 
            conn = dataSource.getConnection();
        } catch (SQLException e) { 
            e.printStackTrace(); 
        }
        return conn;
    }
    //关闭资源 
    public static void close(Connection conn){ 
        if (conn != null) { 
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace(); 
            } 
        } 
    }
    public static void close(Statement st){
        if (st != null) { 
            try { st.close(); }
            catch (SQLException e) { 
                e.printStackTrace(); 
            } 
        } 
    }
    public static void close(ResultSet set){
        if (set != null) { 
            try { set.close(); } 
            catch (SQLException e) { 
                e.printStackTrace();
            } 
        } 
    }
    public static void close(Connection conn,Statement st){
        close(conn);
        close(st);
    }
    public static void close(Connection conn,Statement st,ResultSet rt){ 
        close(conn); 
        close(st);
        close(rt); 
    } 
}
第四节:使用Druid连接池

druid连接池的原理

数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,
会从池中取出一个连接。如果当前池中正在使用的连接数等于maxActive,
则会等待一段时间,等待其他操作释放掉某一个连接,如果这个等待时间超
过了maxWait,则会报错;如果当前正在使用的连接数没有达到maxActive,
则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立
一个连接。在连接使用完毕后,不是将其物理连接关闭,而是将其放入池中
等待其他操作复用。 同时连接池内部有机制判断,如果当前的总的连接数少
于miniIdle,则会建立新的空闲连接,以保证连接数得到miniIdle。如果当前
连接池中某个连接在空闲了timeBetweenEvictionRunsMillis时间后仍然没有
使用,则被物理性的关闭掉。有些数据库连接的时候有超时限制(mysql连接
在8小时后断开),或者由于网络中断等原因,连接池的连接会出现失效的
情况,这时候设置一个testWhileIdle参数为true,可以保证连接池内部定时
检测连接的可用性,不可用的连接会被抛弃或者重建,最大情况的保证从
连接池中得到的Connection对象是可用的。当然,为了保证绝对的可用性,
你也可以使用testOnBorrow为true(即在获取Connection对象时检测其可用性),
不过这样会影响性能。

数据库连接池的原理思想:

连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户
需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接
对象。使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求
访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的
参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大
空闲时间等等。也可以通过其自身的管理机制来监视数据库连接的数量、使用情况。

Druid的优点:

Druid 是目前比较流行的高性能的,分布式列存储的OLAP框架(具体来说是MOLAP)。
它有如下几个特点:
一. 亚秒级查询 
	druid提供了快速的聚合能力以及亚秒级的OLAP查询能力,多租户的设计,是面向用户分析应用的理想方式。
二.实时数据注入 
	druid支持流数据的注入,并提供了数据的事件驱动,保证在实时和离线环境下事件的实效性和统一性 
三.可扩展的PB级存储 
	druid集群可以很方便的扩容到PB的数据量,每秒百万级别的数据注入。即便在加大数据规模的情况下,也能保证时其有效性
四.多环境部署 
	druid既可以运行在商业的硬件上,也可以运行在云上。它可以从多种数据系统中注入数据,包括hadoop,spark, kafka,storm和samza等 
五.丰富的社区 
	druid拥有丰富的社区,供大家学习
4.1使用步骤
4.1.1导入jar包
4.1.2编写工具类
 /**
 * 阿里的数据库连接池
 * 性能最好的
 * Druid
 * */
public class DbUtils {
	//声明连接池对象
	private static DruidDataSource ds;
	static{	
		//实例化配置对象
		Properties properties=new Properties();
		try {//加载配置文件
		     properties.load(DbUtils.class.getClassLoader().getResourceAsStream("database.properties"));
              ds = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);	
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//获取连接对象
	public static Connection getConnection() {
		try {
			return ds.getConnection();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}	
}

数据库配置文件:

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/account
username=root
password=1234
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=5000
4.1.3测试
import java.sql.Connection;

public class Test {
	public static void main(String[] args) throws Exception {
		for(int i=0;i<100;i++) {
			Connection connection=DbUtils.getConnection();
			if(connection!=null) {
				System.out.println("连接成功"+i+"..."+connection.hashCode()+connection.toString());
			}
			connection.close();
		}
	}
}
第五节:Apache组织DBUtils工具类的使用

Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。

5.1 DBUtils简介

DBUtils是java编程中的数据库操作实用工具,小巧简单实用,

1.对于数据表的读操作,可以把结果转换成List,Array,Set等java集合,便于程序员操作。

2.对于数据表的写操作,也变得很简单(只需写sql语句)。

DBUtils包括主要类

DbUtils类:启动类

ResultSetHandler接口:转换类型接口

​ --ArrayHandler类:实现类,把记录转化成数组

​ --ArrayListHandler类:把记录转化成数组,并放入集合中

​ --ColumnListHandler类:取某一列的数据。封装到List中。

​ –ScalarHandler类:适合获取一行一列数据。

​ –BeanHandler类:实现类,把记录转成对象。

​ –BeanListHandler类:实现类,把记录转化成List,使记录为JavaBean类型的对象

QueryRunner类:执行SQL语句的类

5.2 DBUtils工具类+Druid连接池封装
5.2.1 项目准备
  • 创建项目

  • 导入jar包 工具类 配置文件
    commons-dbutils-1.6.jar
    druid-1.1.5.jar

    数据库驱动包

    DruidUtils.java工具类
    database.properties配置文件

5.2.2 实现代码
public class ResultHanlder {

	@Test
	public void testArrayHander() throws SQLException {

		// ArrayHandler:适合取1条记录。把该条记录的每列值封装到一个数组中Object[]
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());
		//1234为参数为sql语句的参数,可以多写
		Object[] query = runner.query("select * from school where empno = ?", new ArrayHandler(), 1234);
		for (Object object : query) {
			System.out.println(object);
		}
	}

	@Test
	public void testArrayListHander() throws SQLException {

		// ArrayHandler:适合取1条记录。把该条记录的每列值封装到一个数组中Object[]
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		List<Object[]> query = runner.query("select * from emp ", new ArrayListHandler());

		for (Object[] objects : query) {
			for (Object object : objects) {

				System.out.println(object);
			}
		}

	}

	@Test
	public void testColumnListHander() throws SQLException {

		// ColumnListHandler:取某一列的数据。封装到List中。
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		List<Object> query = runner.query("select * from emp ", new ColumnListHandler<Object>(2));

		for (Object objects : query) {

			System.out.println(objects);
		}

	}


	@Test
	public void testScalarHandler() throws SQLException {

		// ScalarHandler:适合取单行单列数据
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		Object query = runner.query("select count(*) from emp ", new ScalarHandler());
		System.out.println(query);
	}

	@Test
	public void testBeanHandler() throws SQLException {
		// BeanHandler:适合取单行单列数据
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());
		Employee query = runner.query("select * from emp where empno=1234 ", new BeanHandler<Employee>(Employee.class));
		System.out.println(query.toString());
	}
  
  @Test
	public void testBeanListHandler() throws SQLException {
		// BeanHandler:适合取多行多列数据
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());
		List<Employee> query2 = runner.query("select * from emp", new BeanListHandler<Employee>(Employee.class));
		for (Employee employee : query2) {
			System.out.println(employee);
		}
	}
}
两个问题
1,为什么要使用数据库连接池 
数据库连接池是初始化一定数量的数据库连接放在池中,因为初始化连接池的时候就创建
了若干连接,所以响应系统的时候更快。数据库连接池可以实现连接的复用,避免频繁的
建立连接和关闭连接,降低开销。统一管理资源,限制某一应用的最大连 接数量,避免
某一个应用独占所有数据库资源。 

2.数据库连接池实现原理 
  连接池的工作原理主要由三部分组成,分别为连接池的建立、连接池中连接的使用管理、
连接池的关闭。 	
	
第一、连接池的建立。 一般在系统初始化时,连接池会根据系统配置建立,并在池中创建
了几个连接对象,以便使用 时能从连接池中获取。连接池中的连接不能随意创建和关闭,
这样避免了连接随意建立和关闭造成的系统开销。Java中提供了 很多容器类可以方便的
构建连接池,例如Vector、Stack等。 
		
第二、连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放
对系统的性能有很大的影响。
  其管理策略是:
      当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在
  空闲连接,则将连接分配给客户使用;
      如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没达到
  就重新创建一个连接给请求的客户;如果达到就按设定的最大等待时间进行等待,如果
  超出最大等待时间,则抛出异常给客户。
	  当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过
  就从连接池中删除该连接,否则保留为其他客户服务。 
	 该策略保证了数据库连接的有效复用,避免频繁的建立、释放连接所带来的系统资源
  开销。
第三、连接池的关闭。当应用程序退出时,关闭连接池中所有的连接,释放连接池相关
    的资源,该过程正好与创建相反
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值