zoukankan      html  css  js  c++  java
  • (二十)自定义数据库连接池

    目录


    使用数据库连接池优化数据库性能

    之前我们对数据库的操作,其实是有很大问题的;
    
    因为我们是每次操作数据库之前,都会问数据库要一个连接,用完之后,就把这个链接还给了数据库;
    
    其实数据库连接是重量级的东西,数据库每次创建一个连接出来,都要花老大力气了;
    
    因此,我们应该固定的保存着一些连接,这些连接用完以后,就放在那里,等下次再用,避免每次都问数据库要 ;
    

    连接池

    程序一启动,就问数据库要一定数量的连接,维护在一个地方(连接池);
    
    这样每次,需要连接,就从池中获取,用完之后也不返回给数据库,而是继续保持在池中;起到复用连接的作用;
    
    这种变化是很惊人的;以前10000次访问,就需要创建一千次连接。现在无论多少次访问,都只需要创建连接池中的连接数 ;
    

    编写自定义数据库连接池

    编写连接池需要实现 javax.sql.DataSource 接口。DateSource 接口中定义了 2 个重载 getConnection 的方法 :

    
        Connection getConnection() ;
    
        Connection getConnection(String username,String password) ;
    
    
    • 实现 DateSource 接口,并实现连接池功能的步骤

      a、在DateSource构造器中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中 ;
      
      b、实现getConnection方法,让getConnection方法每次调用时,从Linkedlist中取出一个连接返回给用户 ;
      
      c、当用户使用完Connection以后,调用Connection.close()方法时,Collection对象保证将自己返回到LinkedList中,而不是把conn返给数据库 ;
      
      其中Collection保证将自己返回给LinkedList中是此处编程的难点!!
      

    在实现 Connection getConnection() 的时候,有个问题,就是我们不能简单的从LinkedList 里面获取 Connection 返回,而要是确保 linkedList 里面将按个Connection 对象移除了,否则会造成连接冲突;

    还有一个问题,就是用户在用完 Connection 的时候,会习惯调用 close()方法,这样就导致了连接放给了数据库,而不是返给了我们连接池;


    close()方法加强

    现在就有一个问题,就是如何保证调用 Connection的close()方法,是将连接还给连接池而不是数据库 ?

    这就涉及到,我们对一个类功能进行加强的问题;

    在java里面,通常有三种方法;
    
    
    
    a、写一个子类,覆写父类的方法
    
            这个做法有个致命的缺点:就是必须获得父类的所有信息,向我们这里,继承是基本不可能的!
    
        因为,真正返回给我们的连接是,mysql的驱动类生成的连接,这个类里面,封装了太多的信息:比如:连接的数据库地址、数据库名字、用户名、连接密码。。这些信息 ;
    
        我们要真的想继承它,我们就要在子类中得到这些信息,可惜人家都说private字段,子类也拿不着;子类拿不着,那么子类就连不上数据库。。
    
        除非你去看去mysql的驱动源码,自己把信息拿出来,写在你创建的子类里面,但这跟重写mysql驱动没哈区别了,工程量吓人!
    
        因此,这里放弃这种做法 ;
    
    
    
    
    b、用包装模式
    
        写法:
    
            第一步:定义一个类实现与被增强类相同的接口
    
            第二步:在类中定义一个变量,记住被增强对象
    
            第三步:定义一个构造器,参数接受一个被增强对象的类 
    
            第四步:覆盖我们向增强的方法 ;
    
            第五步:对于不想增强的方法,直接调用被增强对象的方法 ;
    
    
            这样就完美的增强了我们想要的方法;但是也有缺点,就是接口中的每个方法,都要我们去调用被增强对象的方法 ;
    
        接口中的方法少还行,一旦很多,这种代码,我们就要写很多次,,,,,很恶心!
    
        因此,应该考虑动态代理 ;       
    
    
    c、动态代理(aop编程,面向切面编程)
    
        主要是利用拦截;(暂时,我也不会,以后会跟,最多20天以内更新。写于2018年6月12日22:07:53)
    

    代码:

    自定义连接池代码。。

    
    public class MyDataSource implements javax.sql.DataSource {
    
        private static LinkedList<Connection> connections = new LinkedList<>();
    
        static {
            try {
                //        初始化10个连接出来
                for (int i = 0; i < 10; i++) {
                    connections.add(new MyConnection(JdbcUtils.getConnection()));
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new ExceptionInInitializerError(e);
            }
        }
    
        private static MyDataSource myDataSource = new MyDataSource();
    
        public static MyDataSource getDataSource() {
            return myDataSource;
        }
    
        private MyDataSource() {
        }
    
        @Override
        public Connection getConnection() throws SQLException {
    
            if (connections.size() < 1) {
                throw new SQLException("数据库连接正忙,请稍后再试...");
            }
    
            return connections.removeFirst();
        }
    
    
        ....
    
        ....
    
        ....
    
        // 包装器类 ,对MyDataSource类 进行增强
        static class MyConnection implements Connection {
            private Connection connection;
    
    
            public MyConnection(Connection connection) {
                this.connection = connection;
            }
    
        // 其他方法,直接调用 connection的方法。。
            @Override
            public Statement createStatement() throws SQLException {
                return connection.createStatement();
            }
    
            @Override
            public PreparedStatement prepareStatement(String sql) throws SQLException {
                return connection.prepareStatement(sql);
            }
    
        ....
    
        //  重点关注 close方法,对其进行增强,不将连接返回给数据库
        @Override
            public void close() throws SQLException {
                System.out.println("连接池中的剩余连接量:"+connections.size());
                connections.add(this) ;
                System.out.println("成功拦截关闭!将它们返给连接池。。");
    
                System.out.println("连接池中的剩余连接量:"+connections.size());
            }
    
    
        ....
    
        // 还有许多其他方法,不一一列举了,太多了,这也是包装模式的缺点 。。。
    
    
    
    
  • 相关阅读:
    linux利用grep查看打印匹配的下几行或前后几行的命令
    Linux NetHogs监控工具介绍
    db2 查看进程 db2中的常用命令及使用方法
    Linux python <tab>自动补全
    Saltstack pillar组件
    History(历史)命令用法
    Saltstack grains组件
    Saltstack常用模块及API
    文本处理三剑客之AWK的用法
    linux程序调试命令strace
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665701.html
Copyright © 2011-2022 走看看