连接池和DBUtils

用PreparedStatement进行CRUD操作步骤:

  • 拷贝mysql驱动包到模块下,并添加依赖

  • 拷贝JDBCUtils.java工具类和db.properties配置文件到模块下

  • 步骤:

  • 注册驱动,获得连接

    • 预编译sql语句,得到预编译对象

  • 为sql语句设置参数

    • 执行sql语句,处理结果

    • 释放资源

public class Test1_查 {
    public static void main(String[] args) throws Exception{
        //- 注册驱动,获得连接
        Connection connection = JDBCUtils.getConnection();

        //- 预编译sql语句,得到预编译对象
        String sql = "select * from user where id = ?";
        PreparedStatement ps = connection.prepareStatement(sql);

        //- 为sql语句设置参数
        ps.setInt(1,2);

        //- 执行sql语句,处理结果
        ResultSet resultSet = ps.executeQuery();
        // 定义一个User变量
        User user = null;
        while (resultSet.next()) {
            // 取值
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            String password = resultSet.getString("password");
            String nickname = resultSet.getString("nickname");
            // 封装数据
            user = new User(id,username,password,nickname);
        }

        //- 释放资源
        JDBCUtils.release(resultSet,ps,connection);
        System.out.println(user);
    }
}

public class Test2_增 {
    public static void main(String[] args) throws Exception {
        // 1.注册驱动,获得连接
        Connection connection = JDBCUtils.getConnection();

        // 2.预编译sql语句,得到预编译对象
        String sql = "insert into user values(null,?,?,?)";
        PreparedStatement ps = connection.prepareStatement(sql);

        // 3.为sql语句设置参数
        ps.setString(1, "zs");
        ps.setString(2, "123456");
        ps.setString(3, "老张");

        // 4.执行sql语句,处理结果
        int rows = ps.executeUpdate();
        System.out.println("受影响的行数:" + rows);

        // 5.释放资源
        JDBCUtils.release(null,ps,connection);
    }
}

连接池概念

为什么要使用连接池

Connection对象在JDBC使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了(close).每次创建和销毁对象都是耗时操作.需要使用连接池对其进行优化.

程序初始化的时候,初始化多个连接,将多个连接放入到池(集合)中.每次获取的时候,都可以直接从连接池中进行获取.使用结束以后,将连接归还到池中.

  1. 程序一开始就创建一定数量的连接,放在一个容器(集合)中,这个容器称为连接池。

  2. 使用的时候直接从连接池中取一个已经创建好的连接对象, 使用完成之后 归还到池子

  3. 如果池子里面的连接使用完了, 还有程序需要使用连接, 先等待一段时间(eg: 3s), 如果在这段时间之内有连接归还, 就拿去使用; 如果还没有连接归还, 新创建一个, 但是新创建的这一个不会归还了(销毁)

  4. 集合选择LinkedList

    • 增删比较快

    • LinkedList里面的removeFirst()和addLast()方法和连接池的原理吻合

自定义连接池-初级版本

分析

解决办法

  • 创建连接池类

  • 在连接池类中,定义一个LinkedList集合(表示连接池)

  • 在连接池类的静态代码块中,创建固定数量的连接,并存储到LinkedList集合中

  • 提供一个公共的非静态方法来获取连接对象(getAbc)

  • 提供一个公共的非静态方法来归还连接对象(addBack)

  • 提供一个公共的静态方法来获取连接池中连接的数量

  • public class MyDataSource01 {
        //- 在连接池类中,定义一个LinkedList集合(表示连接池)
        private static LinkedList<Connection> pools = new LinkedList<>();

        //- 在连接池类的静态代码块中,创建固定数量的连接,并存储到LinkedList集合中
        static {
            try {
                for (int i = 0; i < 5; i++) {
                    // 创建连接
                    Connection connection = JDBCUtils.getConnection();
                    // 把连接添加到连接池中
                    pools.add(connection);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        //- 提供一个公共的非静态方法来获取连接对象(getAbc)
        public Connection getAbc(){
            // 获取连接池中第一个连接
            Connection connection = pools.removeFirst();
            // 返回连接
            return connection;
        }

        //- 提供一个公共的非静态方法来归还连接对象(addBack)
        public void addBack(Connection connection){
            pools.addLast(connection);
        }

        //- 提供一个公共的静态方法来获取连接池中连接的数量
        public static int size(){
            return pools.size();
        }
    }
    测试:

  • public class Test {
        public static void main(String[] args) throws Exception {
            // 创建连接池对象
            MyDataSource01 dataSource = new MyDataSource01();
            System.out.println("获取连接之前,连接池中连接的数量:"+MyDataSource01.size());// 5

            // 1.注册驱动,获得连接
            Connection connection = dataSource.getAbc();
            System.out.println("获取连接之后,连接池中连接的数量:"+MyDataSource01.size());// 4


            // 2.预编译sql语句,得到预编译对象
            String sql = "select * from user where id = ?";
            PreparedStatement ps = connection.prepareStatement(sql);

            // 3.设置sql语句参数
            ps.setInt(1, 2);

            // 4.执行sql语句,处理结果
            ResultSet resultSet = ps.executeQuery();
            // 定义一个User变量
            User user = null;
            while (resultSet.next()) {
                // 取值
                int id = resultSet.getInt("id");
                String username = resultSet.getString("username");
                String password = resultSet.getString("password");
                String nickname = resultSet.getString("nickname");
                // 封装数据
                user = new User(id, username, password, nickname);
            }

            // 归还连接
            dataSource.addBack(connection);
            System.out.println("获取连接之后,连接池中连接的数量:"+MyDataSource01.size());// 5

            // 5.释放资源
            JDBCUtils.release(resultSet, ps, null);

            System.out.println(user);

        }
    }

  • 自定义连接池-进阶版本

  • 分析

    在初级版本版本中, 我们定义的方法是getAbc(). 因为是自定义的.如果改用李四的自定义的连接池,李四定义的方法是getCon(), 那么我们的源码就需要修改, 这样不方便维护. 所以sun公司定义了一个接口DataSource,让自定义连接池有了规范

    实现

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

  • 分析:

    • 创建连接池类, 实现DataSource接口,重写方法

    • 在连接池类中,定义一个LinkedList集合(表示连接池)

    • 在连接池类的静态代码块中,创建固定数量的连接,并存储到LinkedList集合中

    • 使用重写的方法getConnection,来获取连接对象

    • 提供一个公共的非静态方法来归还连接对象(addBack)

    • 提供一个公共的静态方法来获取连接池中连接的数量

    • public class MyDataSource02 implements DataSource {
          //- 在连接池类中,定义一个LinkedList集合(表示连接池)
          private static LinkedList<Connection> pools = new LinkedList<>();

          //- 在连接池类的静态代码块中,创建固定数量的连接,并存储到LinkedList集合中
          static {
              try {
                  for (int i = 0; i < 5; i++) {
                      // 创建连接
                      Connection connection = JDBCUtils.getConnection();
                      // 把连接添加到连接池中
                      pools.add(connection);
                  }
              } catch (SQLException e) {
                  e.printStackTrace();
              }
          }

          //- 提供一个公共的非静态方法来获取连接对象(getAbc)
         /* public Connection getAbc(){
              // 获取连接池中第一个连接
              Connection connection = pools.removeFirst();
              // 返回连接
              return connection;
          }*/
          @Override
          public Connection getConnection() throws SQLException {
              // 获取连接池中第一个连接
              Connection connection = pools.removeFirst();
              // 返回连接
              return connection;
          }


          //- 提供一个公共的非静态方法来归还连接对象(addBack)
          public void addBack(Connection connection){
              pools.addLast(connection);
          }

          //- 提供一个公共的静态方法来获取连接池中连接的数量
          public static int size(){
              return pools.size();
          }

          @Override
          public Connection getConnection(String username, String password) throws SQLException {
              return null;
          }

          @Override
          public <T> T unwrap(Class<T> iface) throws SQLException {
              return null;
          }

          @Override
          public boolean isWrapperFor(Class<?> iface) throws SQLException {
              return false;
          }

          @Override
          public PrintWriter getLogWriter() throws SQLException {
              return null;
          }

          @Override
          public void setLogWriter(PrintWriter out) throws SQLException {

          }

          @Override
          public void setLoginTimeout(int seconds) throws SQLException {

          }

          @Override
          public int getLoginTimeout() throws SQLException {
              return 0;
          }

          @Override
          public Logger getParentLogger() throws SQLFeatureNotSupportedException {
              return null;
          }
      }
      测试:

    • public class Test {
          public static void main(String[] args) throws Exception {
              // 创建连接池对象
              MyDataSource02 dataSource = new MyDataSource02();
              System.out.println("获取连接之前,连接池中连接的数量:"+MyDataSource02.size());// 5

              // 1.注册驱动,获得连接
              Connection connection = dataSource.getConnection();
              System.out.println("获取连接之后,连接池中连接的数量:"+MyDataSource02.size());// 4


              // 2.预编译sql语句,得到预编译对象
              String sql = "select * from user where id = ?";
              PreparedStatement ps = connection.prepareStatement(sql);

              // 3.设置sql语句参数
              ps.setInt(1, 2);

              // 4.执行sql语句,处理结果
              ResultSet resultSet = ps.executeQuery();
              // 定义一个User变量
              User user = null;
              while (resultSet.next()) {
                  // 取值
                  int id = resultSet.getInt("id");
                  String username = resultSet.getString("username");
                  String password = resultSet.getString("password");
                  String nickname = resultSet.getString("nickname");
                  // 封装数据
                  user = new User(id, username, password, nickname);
              }

              // 归还连接
              dataSource.addBack(connection);
              System.out.println("获取连接之后,连接池中连接的数量:"+MyDataSource02.size());// 5

              // 5.释放资源
              JDBCUtils.release(resultSet, ps, null);

              System.out.println(user);

          }
      }

  • 进阶版后存在的问题分析

  • 实现DataSource接口后,addBack()又有问题了

    • 在进阶版本中, 我们定义的归还连接的方法是addBack(). 因为是自定义的连接池.如果改用李四的自定义的连接池,李四定义的归还连接的方法是back(), 那么我们的源码就需要修改, 这样不方便维护.

    • DataSource接口中也没有定义归还连接的方法,所以只要自定义的连接池,归还连接的方法就可以随便定义,不方便维护.

  • 解决办法: 能不能不引入新的api,直接调用之前的connection.close(),但是这个close不是关闭,而是归还

    • Connection原有的close方法是关闭连接(销毁连接)

    • 增强close方法,把原有关闭连接的功能变成归还连接的功能,这样连接池中就不需要定义归还连接的方法了

  • 继承

    • 条件:可以控制父类, 最起码知道父类的名字

    • 返回的连接对象所属类的类名无法得知,只知道该类是实现了Connection接口

  • 装饰者模式

    • 作用:改写已存在的类的某个方法或某些方法

    • 条件:

      • 装饰类和被装饰类要实现同一个接口

      • 装饰类里面要拿到被装饰类的引用

      • 在装饰类中,对需要增强的方法进行增强

      • 在装饰类中,对不需要增强的方法就调用被装饰类中原有的方法

自定义连接池-终极版本

  • 创建增强的连接类,对close方法进行增强,其余方法依然调用原有的连接对象的方法

  • 创建连接池类, 实现DataSource接口,重写方法

  • 在连接池类中,定义一个LinkedList集合(表示连接池)

  • 在连接池类的静态代码块中,创建固定数量的连接,并存储到LinkedList集合中

  • 使用重写的方法getConnection,来获取连接对象----->增强的连接对象

  • 提供一个公共的静态方法来获取连接池中连接的数量

  • 与进阶版的区别:

    • 连接池类中不需要提供归还连接的方法

    • getConnection获得连接的方法不再返回被增强的连接对象,而是返回增强的连接对象

public class MyConnectionWrapper implements Connection {
    private Connection connection;// 接收被增强的连接对象
    private LinkedList<Connection> pools;// 接收连接池

    public MyConnectionWrapper(Connection connection, LinkedList<Connection> pools) {
        this.connection = connection;
        this.pools = pools;
    }

    @Override
    public void close() throws SQLException {
        // 归还连接--->连接池,被增强的连接对象
        pools.addLast(connection);
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return connection.prepareStatement(sql);
    }
    // ....
}

public class MyDataSource03 implements DataSource {
    //- 在连接池类中,定义一个LinkedList集合(表示连接池)
    private static LinkedList<Connection> pools = new LinkedList<>();

    //- 在连接池类的静态代码块中,创建固定数量的连接,并存储到LinkedList集合中
    static {
        try {
            for (int i = 0; i < 5; i++) {
                // 创建连接
                Connection connection = JDBCUtils.getConnection();
                // 把连接添加到连接池中
                pools.add(connection);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //- 提供一个公共的非静态方法来获取连接对象(getAbc)
   /* public Connection getAbc(){
        // 获取连接池中第一个连接
        Connection connection = pools.removeFirst();
        // 返回连接
        return connection;
    }*/
    @Override
    public Connection getConnection() throws SQLException {
        // 获取连接池中第一个连接
        Connection connection = pools.removeFirst();// 被增强的连接对象

        // 创建增强的连接对象,传入被增强的连接对象,以及连接池
        MyConnectionWrapper myConnectionWrapper = new MyConnectionWrapper(connection, pools);

        // 返回增强的连接对象
        return myConnectionWrapper;
    }


    //- 提供一个公共的非静态方法来归还连接对象(addBack)
    /*public void addBack(Connection connection){
        pools.addLast(connection);
    }*/

    //- 提供一个公共的静态方法来获取连接池中连接的数量
    public static int size(){
        return pools.size();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}

测试类

public class Test {
    public static void main(String[] args) throws Exception {
        // 创建连接池对象
        MyDataSource03 dataSource = new MyDataSource03();
        System.out.println("获取连接之前,连接池中连接的数量:"+MyDataSource03.size());// 5

        // 1.注册驱动,获得连接
        Connection connection = dataSource.getConnection();
        System.out.println("获取连接之后,连接池中连接的数量:"+MyDataSource03.size());// 4


        // 2.预编译sql语句,得到预编译对象
        String sql = "select * from user where id = ?";
        PreparedStatement ps = connection.prepareStatement(sql);

        // 3.设置sql语句参数
        ps.setInt(1, 2);

        // 4.执行sql语句,处理结果
        ResultSet resultSet = ps.executeQuery();
        // 定义一个User变量
        User user = null;
        while (resultSet.next()) {
            // 取值
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            String password = resultSet.getString("password");
            String nickname = resultSet.getString("nickname");
            // 封装数据
            user = new User(id, username, password, nickname);
        }

        // 5.释放资源
        JDBCUtils.release(resultSet, ps, connection);// connection.close(); 归还连接
        System.out.println("获取连接之后,连接池中连接的数量:"+MyDataSource03.size());// 5


        System.out.println(user);

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值