• 自定义一个简单连接池以及常见连接池的使用


    由于使用jdbc的时候,每操作一次都需要获取连接(创建),用完之后把连接释放掉了(销毁)。所以我们可以通过连接池来优化curd操作。

    作用:管理数据库的连接,提高项目的性能。

    思路:就是在连接池初始化的时候存入一定数量的连接,用的时候通过方法获取,不用的时候归还连接即可。注意:所有的连接池都必须实现javax.sql.DataSource接口。

    获取连接方法:Connection getConnection()。

    归还连接方法:connection.close();  //注意,这里会使用装饰者模式,让连接只是归还在了连接池中而不是真正的销毁。

    下面我们开始自定义一个自己的连接池。

     1.初始化连接池。

      首先我们需要定义一个泛型为Connection的List集合,用来存放连接。在这里我们初始容量定义3个。

      然后通过JDBCUtills类来获取连接,并将连接放入List集合中。(关于JDBCUtils工具类的封装,见如下链接

    public class MyDataSource {
    
            //初始化只需要一次就好,所以放在static静态代码块中
        static LinkedList<Connection> list = new LinkedList<>();
        
        static{
            //static不能抛异常,只能try...catch 
            try {
                for(int i = 0; i < 3; i++){
                    Connection conn = JDBCUtils_plus.getConnection();
                    list.add(conn);
                }
                
                
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    2.从连接池中获取连接

      先判断连接池是否为空,若为空,通过循环,创建新的连接放入连接池。若不为空,从List集合中取出第一个连接(removeFirst),然后j将连接返回。

      不过,这里通过装饰者模式包装了一个ConnectionWrapper类,包装类的作用是包装了Connection的close()方法,使得它不会销毁连接,只是将连接放回。

      关于ConnectionWrapper类的创建,后面会详述。

    public static Connection getConnection(){
            if(list.isEmpty()){
                //如果为空,再获取连接进去
                for(int i = 0; i < 3;i++){
                    try {
                        list.add(JDBCUtils_plus.getConnection());
                    } catch (ClassNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                
            }
            Connection conn = list.removeFirst();
            System.out.println("获取连接池");
                    //通过构造方法将connection类传入包装类中
            ConnectionWrapper cw = new ConnectionWrapper(conn,list);
                    //返回包装类
            return cw;
            
        }
    }

    3.利用装饰者模式,创建Connection的包装类ConnectionWrapper

    装饰者模式的具体介绍参照装饰者模式

    装饰者模式中,装饰者和被装饰者需要继承同一个类或者实现同一个接口。由于Connection本身就是一个接口,所以很自然的让装饰者继承这个接口。

    通过查看Connection接口的api发现,接口中的抽象方法实在是太多了。如果我们直接让装饰者类继承,需要重写太多方法。

    以下为部分方法:

    所以在这里,我们需要使用适配器模式,新增加一个类ConnectionAdapter,让它来实现Connection接口,让装饰者类继承ConnectionAdapter类,这样就可以只重写需要用的方法啦。

    该类部分截图:

    装饰者类:

    public class ConnectionWrapper extends ConnectionAdapter {
    
        private Connection conn;
        private LinkedList<Connection> list;
        public ConnectionWrapper() {
            
        }
      //通过构造方法将被装饰者类传入进来并赋值给内部类。将List集合也传进来,因为有归还连接的操作。
    public ConnectionWrapper(Connection conn,LinkedList<Connection> list) { this.conn = conn; this.list = list; } @Override
      //重写close方法,归还连接。
    public void close() throws SQLException { System.out.println("前"+list.size()); list.addLast(this); System.out.println("后"+list.size()); }
    //以下两个方法就调用以前的方法就行 @Override
    public Statement createStatement() throws SQLException { // TODO Auto-generated method stub return conn.createStatement(); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { // TODO Auto-generated method stub return conn.prepareStatement(sql); }

    测试类:

    public class Test {
    
        public static void main(String[] args) throws SQLException {
            Connection conn = MyDataSource.getConnection();
                    //注意:这里的conn已经不是单纯的Connection了,它是实际传过来的装饰类ConnectionWrapper
            String sql = "select * from student";
            PreparedStatement st  = conn.prepareStatement(sql);
            ResultSet rs = st.executeQuery();
            while(rs.next()){
                System.out.println(
                        rs.getString("id")+"  "+rs.getString("name")
                        +"   "+rs.getString("score"));
            }
                   //这里调用的也不是Connection以前的close()方法了,这里是包装类的增强close()方法。不销毁连接,只归还连接。
            conn.close();
        }
    }

    运行结果如下:

    以上,就是一个简易的jdbc连接池。

    然而现实有两个比较常用的,封装好的连接池,他们分别是DBCP和C3P0,以下介绍他们的用法:

    一.DBCP连接池

    apache组织出品。

     1.导入jar包(commons-dbcp-1.4.jar和commons-pool-1.5.6.jar)

    (emmmm请无视中间的dbutils的jar包......)

    2.使用

      a.硬编码(不推荐使用)

      以下是硬编码方式的配置信息:

         //创建连接池
            BasicDataSource ds = new BasicDataSource();
            
            //配置信息
            ds.setDriverClassName("com.mysql.jdbc.Driver");
            ds.setUrl("jdbc:mysql:///exercise");
            ds.setUsername("root");
            ds.setPassword("123456");

      b.采用配置文件的方式读取配置信息。这里拿properties文件举例。(名称为dbcp.properties)

    代码如下:

      //存放配置文件
        Properties prop = new Properties();
        prop.load(new FileInputStrea("src/dbcp.properties"))            
        //创建连接池
        DataSource ds = new BasicDataSourceFactory().createDataSource(prop);   
       Connection conn=ds.getConnection();

    二.C3P0连接池(比较常见)

    hibernate和spring使用,有自动回收空闲连接的功能。

    1.导入jar包(c3p0-0.9.1.2.jar)

    2.使用

      a.硬编码:

    ComboPooledDataSource ds = new ComboPooledDataSource();
            
            //设置基本参数
            ds.setDriverClass("com.mysql.jdbc.Driver");
            ds.setJdbcUrl("jdbc:mysql:///exercise");
            ds.setUser("root");
            ds.setPassword("123456");
            
            Connection conn=ds.getConnection();

      b.读取配置文件

      注意:配置文件的名称:c3p0.properties 或者 c3p0-config.xml时,可以直接使用new ComboPooledDataSource()来获取配置文件(默认配置)。

          new ComboPooledDataSource(String configName)//使用命名的配置 若配置的名字找不到,使用默认的配置

      以下用properties文件举例:

      代码如下:

       //由于配置文件写的默认名字,这里使用无参构造
        ComboPooledDataSource ds =new ComboPooledDataSource();
        Connection conn=ds.getConnection();
  • 相关阅读:
    Codeforces 1255B Fridge Lockers
    Codeforces 1255A Changing Volume
    Codeforces 1255A Changing Volume
    leetcode 112. 路径总和
    leetcode 129. 求根到叶子节点数字之和
    leetcode 404. 左叶子之和
    leetcode 104. 二叉树的最大深度
    leetcode 235. 二叉搜索树的最近公共祖先
    450. Delete Node in a BST
    树的c++实现--建立一棵树
  • 原文地址:https://www.cnblogs.com/tonbby/p/9043347.html
Copyright © 2020-2023  润新知