JDBC手写连接池及才c3p0,dbcp链接池原理指南

JDBC实现连接池&DBUtils

今日内容介绍

  • 使用DBCP,C3P0连接池完成基本数据库的操作

  • 使用DBUtils完成CRUD的操作

今日内容学习目标

  • 使用C3P0创建数据源DataSource。

  • 使用DBCP创建据源DataSource。

  • 能够使用JDBC简化工具包DBUtils完成单表的增删改查操作。

一,使用连接池重写工具类

1.为什么使用连接池重写工具类

  • 1.因为每次创建和销毁连接都会带来较大的系统开销

  • 2.每次创建和销毁连接都要消耗大概0.05~1s的时间。

  • 3.可以防止大量用户并发访问数据库服务器。

  • Connection对象在JDBC使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了.每次创建和销毁对象都是耗时操作.需要使用连接池对其进行优化.程序初始化的时候,初始化多个连接,将多个连接放入到池(集合)中.每次获取的时候,都可以直接从连接池中进行获取.使用结束以后,将连接归还到池中.

2.连接池原理

JDBC手写连接池及才c3p0,dbcp链接池原理指南_第1张图片

  • 目的:解决建立数据库连接耗费资源和时间很多的问题,提高性能。

3.编写连接池

3.1步骤

  • 创建一个类,定义LinkedList集合作为连接池,在静态代码块中,向集合里面添加5个连接对象

  • 添加addBack()方法,用作归还连接

  • 代码:

  public class MyDataSource {
      //连接池
      static LinkedList pool = new LinkedList<>();
      //初始化连接
      static{
          try {
              for(int i = 0;i < 5;i++){
                  pool.add(JdbcUtils.getConnection());
              }
          } catch (SQLException e) {
              e.printStackTrace();
          }
          
      }
      //定义一个方法,从池子中获取connection,从头部获取
      public Connection getConnectionFromPool(){
          if (pool.size() > 0) {
              //池子中有connection
              return pool.removeFirst();
          }else {
              //如果池子中没有connection,则先加入等待队列,等待队列满了的话就新建connection(新建的              //connection是不需要放回池子的,用完后直接销毁)
              return JDBCUtil.getConnection();
          }
      }
      //定义一个方法,将connection放回池子中(如果是新创建的connection则直接销毁)
      public void addBack(Connection connection){
          //pool.addLast(connection);//免不了会将新建的connection添加进池子;
          try {
              //写一个自己的connection,然后重写close()方法,通过close()方法来添加进池子。
              connection.close();//免不了会将池子中的connection销毁
          } catch (SQLException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
      }
      //返回pool里面连接的个数
      public int getCount(){
          return pool.size();
      }
      
  
  }

3.2编写连接池遇到的问题

  • 如果新建了connection,用完之后怎么判别是原池子中的connection(需要放回去),还是新建的connection(需要销毁)。

3.3解决办法(自定义一个Connection,重写close方法)

  • 继承条件:可以控制父类的构造

  • 装饰者模式

    目的:改写已存在的类的某个方法或某些方法,装饰设计模式(包装模式)

      
      条件:1.包装类和被包装类实现的是同一个接口
          2.包装类里面要拿到被包装类的引用

步骤:

  1. 编写一个类实现一个接口,为被包装类

  2. 编写一个类,实现与被包装类相同的接口。(具备相同的行为)

  3. 定义一个被包装类类型的变量。

  4. 定义构造方法,把被包装类类的对象注入,给被包装类变量赋值。

  5. 对于不需要改写的方法,调用被包装类类原有的方法。

  6. 对于需要改写的方法,写自己的代码。

  • 动态代理(类似装饰者模式,此处不学)

3.4datasource接口概述

  • Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商(用户)需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!

  • 常见的连接池:DBCP、C3P0。

4.常用连接池

4.1 dbcp

4.1.1 dbcp概念

JDBC手写连接池及才c3p0,dbcp链接池原理指南_第2张图片

  • DBCP:Apache推出的Database Connection Pool

核心API:

  • basicDatasource

  • basicDatasourceFactory

4.1.2使用步骤

  • 添加jar包 commons-dbcp-1.4.jar commons-pool-1.5.6.jar

  • 添加配置文件到src目录

  • 编写数据源工具类

  1. 通过配置文件来编写

  
  
  public class DBCPUtils {
  
      static DataSource ds;
  
      static {
          //只需要初始化一次
          try {
              Properties p = new Properties();
  
              InputStream is =                      JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
              // InputStream is = new FileInputStream("src/dbcpconfig.properties");
              p.load(is);
              ds = BasicDataSourceFactory.createDataSource(p);
          } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          } catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
      }
      
      
      // 创建连接
          public static Connection getConnection() throws SQLException {
              
              // DriverManager.getConnection(url, user, password);  Connection
              
              Connection connection = ds.getConnection();
              return connection;
  
          }
  
          // 释放资源
          public static void release(ResultSet resultSet, Statement statement, Connection connection) {
              
              if (resultSet != null) {
                  try {
                      resultSet.close();
                  } catch (SQLException e) {
                      e.printStackTrace();
                  }
              }
  
              if (statement != null) {
                  try {
                      statement.close();
                  } catch (SQLException e) {
                      e.printStackTrace();
                  }
              }
  
              if (connection != null) {
                  try {
                      connection.close();//不要关注方法名,关注连接来源
                  } catch (SQLException e) {
                      e.printStackTrace();
                  }
              }
  
          }
  
  
  }

  1. 通过硬编码来表写(不需要配置文件.了解一下)

      
      DataSource basicDataSource = new BasicDataSource();
      basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
      basicDataSource.setUrl("jdbc:mysql://localhost:3306/day01_1");
      basicDataSource.setUsername("root");
      basicDataSource.setPassword("123456");

4.2 c3p0

4.2.1 c3p0概念

JDBC手写连接池及才c3p0,dbcp链接池原理指南_第3张图片

  • C3P0开源免费的连接池!目前使用它的开源项目有:Spring、Hibernate等。使用第三方工具需要导入jar包,c3p0使用时还需要添加配置文件c3p0-config.xml

4.2.2使用步骤

  • 添加jar包

  • 编写配置文件c3p0-config.xml,放在src中(注:文件名一定不要写错)

  1. 通过配置文件来编写

  
  public class C3P0Utils {
      //创建一个连接池对象
      static DataSource ds = new ComboPooledDataSource();
      
      //从池中获得一个连接
      public static Connection getConnection() throws SQLException{
          return ds.getConnection();
      }
      
      //释放资源
      public static void release(ResultSet rs,Statement stmt,Connection conn){
          if(rs!=null){
              try {
                  rs.close();
              } catch (SQLException e) {
                  throw new RuntimeException(e);
              }
              rs = null;
          }
          if(stmt!=null){
              try {
                  stmt.close();
              } catch (SQLException e) {
                  throw new RuntimeException(e);
              }
              stmt = null;
          }
          
          if(conn!=null){
              try {
                  conn.close();//放心的关。是否关闭取决连接是怎么来的
              } catch (SQLException e) {
                  throw new RuntimeException(e);
              }
              conn = null;
          }
      }
  }

  1. 通过硬编码来编写(不需要配置文件.了解一下)

  
      DataSource cpds = new ComboPooledDataSource();
      cpds.setDriverClass("com.mysql.jdbc.Driver"); // loads the jdbc driver
      cpds.setJdbcUrl("jdbc:mysql://localhost:3306/day10");
      cpds.setUser("root");
      cpds.setPassword("123");
4.3 druid连接池

Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。

druid连接池的使用

  • 使用硬编码方式

  
  //创建一个DruidDataSource()对象
          DruidDataSource dataSource = new DruidDataSource();
          //设置用户名
          dataSource.setUsername("root");
          //设置密码
          dataSource.setPassword("123");
          //设置驱动类名
          dataSource.setDriverClassName("com.mysql.jdbc.Driver");
          //设置初始化连接数
          dataSource.setInitialSize(10);
          //获得连接
          Connection connection = dataSource.getConnection();
  • 使用配置文件

    //创建Properties对象

      
          Properties properties = new Properties();
          //加载配置文件
          properties.load(new FileInputStream("src/druidconfig.properties"));
          //创建使用连接池工厂创建连接池
          DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
          //获得连接
          Connection connection = dataSource.getConnection();

二,使用DBUtils 增删改查的操作(第一个数据库框架)

1.案例分析

  • 简化JDBC代码开发,本案例我们将采用apache commons组件一个成员:DBUtils。

  • DBUtils就是JDBC的简化开发工具包。需要使用技术:连接池(获得连接)、SQL语句都没有少

2.案例相关知识

2.1javaBean组件

JavaBean就是一个类,在开发中常用于封装数据。具有如下特性

1.需要实现接口:java.io.Serializable ,通常偷懒省略了。2.提供私有字段:private 类型 字段名;3.提供getter/setter方法:4.提供无参构造

  
      public class Category {
          private String cid;
          private String cname;
      
          public String getCid() {
              return cid;
          }
          public void setCid(String cid) {
              this.cid = cid;
          }
          public String getCname() {
              return cname;
          }
          public void setCname(String cname) {
              this.cname = cname;
          }
      
      }

3.DBUtils完成CRUD

3.DBUtils完成CRUD

3.DBUtils完成CRUD

3.1概述
  1. DBUtils是java编程中的数据库操作实用工具,小巧简单实用。 第一个操作数据库框架(jar),

  2. DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。

  3. Dbutils三个核心功能介绍

QueryRunner中提供对sql语句操作的API. update(), query()

ResultSetHandler接口,用于定义select操作后,怎样封装结果集.

DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

3.2QueryRunner核心类
  • QueryRunner(DataSource ds) ,提供数据源(连接池),DBUtils底层自动维护连接connection

  • update(String sql, Object... params) ,执行更新数据 insert update delete 参数就是一个数组,参数个数取决于语句中?的个数

  • query(String sql, ResultSetHandler rsh, Object... params) ,执行查询 select

3.3ResultSetHandler结果集处理类
Handler类型 说明
ArrayHandler 将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值
ArrayListHandler 将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。
BeanHandler 将结果集中第一条记录封装到一个指定的javaBean中。
BeanListHandler 将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
ColumnListHandler 将结果集中指定的列的字段值,封装到一个List集合中
KeyedHandler 将结果集中每一条记录封装到Map,在将这个map集合做为另一个Map的value,另一个Map集合的key是指定的字段的值。
MapHandler 将结果集中第一条记录封装到了Map集合中,key就是字段名称,value就是字段值
MapListHandler 将结果集中每一条记录封装到了Map集合中,key就是字段名称,value就是字段值,在将这些Map封装到List集合中。
ScalarHandler 它是用于单个数据。例如select count(*) from 表操作。
3.4练习
3.4.1开发步骤:
  1. 创建项目,并导入jar包

  2. 创建连接池

  3. 编写测试类

3.4.2增加
  
  //向user表添加一条数据
      
      @Test
      public void  insert() throws SQLException{
          //创建queryRunner对象
          QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
          
          //String sql = "insert into user values(null,'aaa','111','露西')";
          String sql = "insert into user values(?,?,?,?)";
          
          Object[] params ={null,"aaa","111","露西"};
          queryRunner.update(sql, params);
          
      }
3.4.3更新

  
      //把用户名是aaa的user密码改成222
      
      @Test
      public  void update() throws SQLException{
          //创建queryRunner对象
          QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
          
          String sql = "update user set password = ? where username = ?";
          Object[] params={"222","aaa"};
          queryRunner.update(sql, params);
          
      }
3.4.4删除

  
      //把用户名是aaa的user给删除
      
      @Test
      public  void delete() throws SQLException{
          //创建queryRunner对象
          QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
          
          String sql = "delete from user where username = ?";
          Object[] params={"aaa"};
          queryRunner.update(sql, params);
          
      }
3.4.5通过id查询
  
      //查询id为1的用户信息
      
      @Test
      public  void selectById() throws SQLException{
          //创建queryRunner对象
          QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
          String sql = "select *from user where id = ?";
          Object[] params = {1};
          
          User user = queryRunner.query(sql, new BeanHandler<>(User.class), params);
          
          System.out.println(user.toString());
          
      }

3.4.6查询所有列
  
      
      //查询所有的用户信息
      @Test
      public  void selectAll() throws SQLException{
          //创建queryRunner对象
          QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
          
          String sql = "select *from user";
          Object[] params = {};
          
          List list = queryRunner.query(sql, new BeanListHandler<>(User.class), params);
          
          System.out.println(list.toString());
          
      }

3.4.7 总记录数

  
      //统计用户的个数
      
      @Test
      public  void getCount() throws SQLException{
          //创建queryRunner对象
          QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
          
          String sql = "select count(*) from user";
          
          Long n = (Long) queryRunner.query(sql, new ScalarHandler());
          
          System.out.println(n.intValue());
      }

最基本的要求:

1.会使用DBCP、C3P0、Druid连接池。

2.会使用DBUtils

目标:

1.理解连接池的概念及作用。

2.封装C3P0Util。

3.使用DBUtils和DruidUtil结合,实现对数据的增删改查操作。(最起码得写10个操作)

4.如果有兴趣,可以实现自定义连接池。

你可能感兴趣的:(JDBC)