zoukankan      html  css  js  c++  java
  • 【Java EE 学习 16 上】【dbcp数据库连接池】【c3p0数据库连接池】

    一、回顾之前使用的动态代理的方式实现的数据库连接池:

    代码:

     1 package day16.utils;
     2 
     3 import java.io.IOException;
     4 import java.lang.reflect.InvocationHandler;
     5 import java.lang.reflect.Method;
     6 import java.lang.reflect.Proxy;
     7 import java.sql.Connection;
     8 import java.sql.DriverManager;
     9 import java.sql.SQLException;
    10 import java.util.LinkedList;
    11 import java.util.Properties;
    12 
    13 public class JDBCUtils {
    14     private static LinkedList<Connection>pool=new LinkedList<Connection>();//定义连接池,使用LinkedList能提高效率
    15     static{
    16         Properties properties=new Properties();
    17         try {
    18             properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties"));
    19             String driver=properties.getProperty("driver");
    20             String username=properties.getProperty("username");
    21             String password=properties.getProperty("password");
    22             String url=properties.getProperty("url");
    23             int connectionMaxNum=Integer.parseInt(properties.getProperty("connectionMaxNum"));
    24             Class.forName(driver);
    25             for(int i=0;i<connectionMaxNum;i++)
    26             {
    27                 final Connection conn=DriverManager.getConnection(url, username, password);
    28                 //关键的一步:进行代理设置。
    29                 Object proxy=Proxy.newProxyInstance(
    30                         JDBCUtils.class.getClassLoader()
    31                         , new Class[]{Connection.class}, 
    32                         new InvocationHandler() {
    33                             @Override
    34                             public Object invoke(Object proxy, Method method, Object[] args)
    35                                     throws Throwable {
    36                                 //如果调用了close方法,则不要关闭连接,而应当将连接回收。
    37                                 if(method.getName().equals("close"))
    38                                 {
    39                                     synchronized(pool)
    40                                     {
    41                                         pool.addLast((Connection) proxy);//这里进行强制转换
    42                                         System.out.println("调用了close方法!回收 "+proxy+" ,剩余连接数为"+pool.size());
    43                                         pool.notify();//从等待池中唤醒任意一条线程
    44                                     }
    45                                     return null;//返回值是null表名拦截该方法的执行。这里的return位置非常重要,一不小心就会是的创建反射对象失败
    46                                 }
    47                                 //如果调用了其他的方法,则要放行
    48                                 else
    49                                 {
    50                                     System.out.println("调用了 "+method.getName()+" 方法,放行!");
    51                                     return method.invoke(conn, args);//注意这里的对象是conn,而不是其它对象
    52                                 }
    53                             }
    54                         });
    55 //                System.out.println(proxy);
    56                 pool.addLast((Connection) proxy);//这里添加的一定是被代理的对象
    57             }
    58             System.out.println(pool);
    59         } catch (IOException e) {
    60             e.printStackTrace();
    61         } catch (ClassNotFoundException e) {
    62             e.printStackTrace();
    63         } catch (SQLException e) {
    64             e.printStackTrace();
    65         }
    66     }
    67     //获得连接对象的方法
    68     public static Connection getConnection()
    69     {
    70         synchronized (pool) {
    71             if(pool.size()==0)
    72             {
    73                 System.out.println("连接池中没有可用连接,等待中------------");
    74                 try {
    75                     pool.wait();//等待的方式,使用的是pool*************************
    76                 } catch (InterruptedException e) {
    77                     e.printStackTrace();
    78                 }
    79                 return getConnection();//递归调用该方法目的是解锁之后重新获得连接
    80             }
    81             else
    82             {
    83                 Connection conn=pool.removeFirst();
    84                 System.out.println("分配一条连接,剩余连接数目为"+pool.size());
    85                 return conn;
    86             }
    87         }
    88     }
    89 }
    JDBCUtils.java

    测试:

    public void testByProxy() throws SQLException
        {
            Connection conn1=JDBCUtils.getConnection();
            Connection conn2=JDBCUtils.getConnection();
            Connection conn3=JDBCUtils.getConnection();
            conn1.close();
            Connection conn4=JDBCUtils.getConnection();
        }
    测试代码

    运行结果:

    调用了 toString 方法,放行!
    调用了 toString 方法,放行!
    调用了 toString 方法,放行!
    [com.mysql.jdbc.JDBC4Connection@9c7650, com.mysql.jdbc.JDBC4Connection@1b9c3f, com.mysql.jdbc.JDBC4Connection@af28ad]
    分配一条连接,剩余连接数目为2
    分配一条连接,剩余连接数目为1
    分配一条连接,剩余连接数目为0
    调用了 toString 方法,放行!
    调用了close方法!回收 com.mysql.jdbc.JDBC4Connection@9c7650 ,剩余连接数为1
    分配一条连接,剩余连接数目为0
    运行结果

    和之前的相比有些改进:连接池使用LinkedList,效率更高。

    功能增强的方式有两种:

      1.使用动态代理的方式

      2.使用包装的方式

    实际上实现数据库连接池只需要实现一个接口:DataSource,然后改连接池就实现了标准化~

    二、使用动态代理实现数据库连接池。

    1.数据库连接池动态代理实现方式

    package day16.utils;
    //实现DataSource接口使用反射机制实现数据库连接池。
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.SQLFeatureNotSupportedException;
    import java.util.LinkedList;
    import java.util.Properties;
    import java.util.logging.Logger;
    
    import javax.sql.DataSource;
    
    public class DBCPPools implements DataSource{
        private  LinkedList<Connection>pools=new LinkedList<Connection>();
        public DBCPPools()
        {
            try {
                Properties config=new Properties();
                config.load(DBCPPools.class.getClassLoader().getResourceAsStream("config.properties"));
                Class.forName(config.getProperty("driver"));
                String url=config.getProperty("url");
                String username=config.getProperty("username");
                String password=config.getProperty("password");
                for(int i=0;i<3;i++)
                {
                    final Connection conn=DriverManager.getConnection(url,username,password);
                    Object proxy=Proxy.newProxyInstance(
                            DBCPPools.class.getClassLoader(),
                            new Class[]{Connection.class}, 
                            new InvocationHandler() {
                                @Override
                                public Object invoke(Object proxy, Method method, Object[] args)
                                        throws Throwable {
                                    if(method.getName().equals("close"))
                                    {
                                        synchronized(pools)
                                        {
                                            pools.addLast((Connection) proxy);
                                            System.out.println("调用了close方法!回收 "+proxy+" ,剩余连接数为"+pools.size());
                                            pools.notify();
                                        }
                                        return null;
                                    }
                                    else
                                    {
    //                                    System.out.println(proxy(这里不能写上proxy,否则异常报出!!!!为什么????)+"调用了 "+method.getName()+" 方法,放行!");
                                        System.out.println("调用了 "+method.getName()+" 方法,放行!");
                                        return method.invoke(conn, args);
                                    }
                                }
                            });
                    pools.add((Connection) proxy);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //最重要的是实现这个方法。
        @Override
        public  Connection getConnection(){
            synchronized(pools)
            {
                if(pools.size()==0)
                {
                    System.out.println("连接池中没有可用连接,等待中------------");
                    try {
                        pools.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return getConnection();
                }
                else
                {
                    Connection conn=pools.removeFirst();
                    System.out.println("分配一条连接,剩余连接数目为"+pools.size());
                    return conn;
                }
            }
        }
        @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 <T> T unwrap(Class<T> iface) throws SQLException {
            return null;
        }
        @Override
        public boolean isWrapperFor(Class<?> iface) throws SQLException {
            return false;
        }
        @Override
        public Connection getConnection(String username, String password)
                throws SQLException {
            return null;
        }
        @Override
        public Logger getParentLogger() throws SQLFeatureNotSupportedException {
            return null;
        }
    }
    DBCPPools.java

    2.测试代码

    public void testImplementsDataSourceInterfaceByProxy() throws SQLException
        {
            DBCPPools pool=new DBCPPools();
            Connection conn1=pool.getConnection();
            System.out.println(conn1);
            System.out.println();
            
            Connection conn2=pool.getConnection();
            System.out.println(conn2);
            System.out.println();
            
            Connection conn3=pool.getConnection();
            System.out.println(conn3);
            System.out.println();
    //        conn1.close();//如果这里没有注释掉,则可以拿到第四条连接,连接池大小默认为3
            Connection conn4=pool.getConnection();//第四条连接因为拿不到连接而进入等待池中。
            System.out.println(conn4);
        }

    运行结果:

    分配一条连接,剩余连接数目为2
    调用了 toString 方法,放行!
    com.mysql.jdbc.JDBC4Connection@46530
    
    分配一条连接,剩余连接数目为1
    调用了 toString 方法,放行!
    com.mysql.jdbc.JDBC4Connection@8f5f75
    
    分配一条连接,剩余连接数目为0
    调用了 toString 方法,放行!
    com.mysql.jdbc.JDBC4Connection@c3feb6
    
    连接池中没有可用连接,等待中------------

    将关闭连接的代码放开:

    分配一条连接,剩余连接数目为2
    调用了 toString 方法,放行!
    com.mysql.jdbc.JDBC4Connection@912767
    
    分配一条连接,剩余连接数目为1
    调用了 toString 方法,放行!
    com.mysql.jdbc.JDBC4Connection@1b1ebe5
    
    分配一条连接,剩余连接数目为0
    调用了 toString 方法,放行!
    com.mysql.jdbc.JDBC4Connection@1f61490
    
    调用了 toString 方法,放行!
    调用了close方法!回收 com.mysql.jdbc.JDBC4Connection@912767 ,剩余连接数为1
    分配一条连接,剩余连接数目为0
    调用了 toString 方法,放行!
    com.mysql.jdbc.JDBC4Connection@912767

    三、使用包装的方法实现自定义数据库连接池

      1.包装对象:Connection类,这里作为数据库连接池的一个内部类(MyConnection)。

      2.使用包装的方法实现的数据库连接池:

      1 package day16.utils;
      2 
      3 import java.io.PrintWriter;
      4 import java.sql.Array;
      5 import java.sql.Blob;
      6 import java.sql.CallableStatement;
      7 import java.sql.Clob;
      8 import java.sql.Connection;
      9 import java.sql.DatabaseMetaData;
     10 import java.sql.DriverManager;
     11 import java.sql.NClob;
     12 import java.sql.PreparedStatement;
     13 import java.sql.SQLClientInfoException;
     14 import java.sql.SQLException;
     15 import java.sql.SQLFeatureNotSupportedException;
     16 import java.sql.SQLWarning;
     17 import java.sql.SQLXML;
     18 import java.sql.Savepoint;
     19 import java.sql.Statement;
     20 import java.sql.Struct;
     21 import java.util.LinkedList;
     22 import java.util.Map;
     23 import java.util.Properties;
     24 import java.util.concurrent.Executor;
     25 import java.util.logging.Logger;
     26 
     27 import javax.sql.DataSource;
     28 
     29 //测试使用包装的方法定义一个数据库连接池
     30 public class MyDBCPpool implements DataSource{
     31     private LinkedList<Connection> pool =new LinkedList<Connection>();
     32     public MyDBCPpool()
     33     {
     34         Properties properties=new Properties();
     35         try {
     36             properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties"));
     37             String driver=properties.getProperty("driver");
     38             String username=properties.getProperty("username");
     39             String password=properties.getProperty("password");
     40             String url=properties.getProperty("url");
     41             int connectionMaxNum=Integer.parseInt(properties.getProperty("connectionMaxNum"));
     42             Class.forName(driver);
     43             for(int i=0;i<connectionMaxNum;i++)
     44             {
     45                 Connection conn=DriverManager.getConnection(url,username,password);
     46                 MyConnection connection =new MyConnection(conn);
     47                 pool.addLast(connection);
     48             }
     49         }
     50         catch(Exception e)
     51         {
     52             e.printStackTrace();
     53         }
     54     }
     55     @Override
     56     public Connection getConnection() throws SQLException {
     57         System.out.println(pool);
     58         synchronized(pool)
     59         {
     60             if(pool.size()==0)
     61             {
     62                 try {
     63                     pool.wait();
     64                 } catch (InterruptedException e) {
     65                     e.printStackTrace();
     66                 }
     67                 return getConnection();
     68             }
     69             else
     70             {
     71                 Connection conn=pool.removeFirst();
     72                 System.out.println("分配出一条连接:"+conn+" 剩余"+pool.size()+" 条连接!");
     73                 return conn;
     74             }
     75         }
     76     }
     77     @Override
     78     public Connection getConnection(String username, String password)
     79             throws SQLException {
     80         return null;
     81     }
     82     @Override
     83     public PrintWriter getLogWriter() throws SQLException {
     84         return null;
     85     }
     86     @Override
     87     public void setLogWriter(PrintWriter out) throws SQLException {
     88     }
     89     @Override
     90     public void setLoginTimeout(int seconds) throws SQLException {
     91     }
     92     @Override
     93     public int getLoginTimeout() throws SQLException {
     94         return 0;
     95     }
     96 //    @Override
     97     public Logger getParentLogger() throws SQLFeatureNotSupportedException {
     98         return null;
     99     }
    100     @Override
    101     public <T> T unwrap(Class<T> iface) throws SQLException {
    102         return null;
    103     }
    104     @Override
    105     public boolean isWrapperFor(Class<?> iface) throws SQLException {
    106         return false;
    107     }
    108     class MyConnection implements Connection
    109     {
    110         private Connection conn;
    111         public MyConnection(Connection conn){
    112             this.conn=conn;
    113         }
    114         //重写close方法
    115         @Override
    116         public void close() throws SQLException {
    117             synchronized(pool)
    118             {120                 pool.addLast(this);
                System.out.println(this+"还连接!剩余连接数:"+pool.size());
    121 pool.notify(); 122 } 123 } 124 @Override 125 public <T> T unwrap(Class<T> iface) throws SQLException { 126 return conn.unwrap(iface); 127 } 128 @Override 129 public boolean isWrapperFor(Class<?> iface) throws SQLException { 130 return conn.isWrapperFor(iface); 131 } 132 @Override 133 public Statement createStatement() throws SQLException { 134 return conn.createStatement(); 135 } 136 @Override 137 public PreparedStatement prepareStatement(String sql) 138 throws SQLException { 139 return conn.prepareStatement(sql); 140 } 141 @Override 142 public CallableStatement prepareCall(String sql) throws SQLException { 143 return conn.prepareCall(sql); 144 } 145 @Override 146 public String nativeSQL(String sql) throws SQLException { 147 return conn.nativeSQL(sql); 148 } 149 @Override 150 public void setAutoCommit(boolean autoCommit) throws SQLException { 151 conn.setAutoCommit(autoCommit); 152 } 153 @Override 154 public boolean getAutoCommit() throws SQLException { 155 return conn.getAutoCommit(); 156 } 157 @Override 158 public void commit() throws SQLException { 159 conn.commit(); 160 } 161 @Override 162 public void rollback() throws SQLException { 163 conn.rollback(); 164 } 165 @Override 166 public boolean isClosed() throws SQLException { 167 return conn.isClosed(); 168 } 169 @Override 170 public DatabaseMetaData getMetaData() throws SQLException { 171 return conn.getMetaData(); 172 } 173 @Override 174 public void setReadOnly(boolean readOnly) throws SQLException { 175 conn.setReadOnly(readOnly); 176 } 177 @Override 178 public boolean isReadOnly() throws SQLException { 179 return conn.isReadOnly(); 180 } 181 @Override 182 public void setCatalog(String catalog) throws SQLException { 183 conn.setCatalog(catalog); 184 } 185 @Override 186 public String getCatalog() throws SQLException { 187 return conn.getCatalog(); 188 } 189 @Override 190 public void setTransactionIsolation(int level) throws SQLException { 191 conn.setTransactionIsolation(level); 192 } 193 @Override 194 public int getTransactionIsolation() throws SQLException { 195 return conn.getTransactionIsolation(); 196 } 197 @Override 198 public SQLWarning getWarnings() throws SQLException { 199 return conn.getWarnings(); 200 } 201 @Override 202 public void clearWarnings() throws SQLException { 203 conn.clearWarnings(); 204 } 205 @Override 206 public Statement createStatement(int resultSetType, 207 int resultSetConcurrency) throws SQLException { 208 return conn.createStatement(resultSetType, resultSetConcurrency); 209 } 210 @Override 211 public PreparedStatement prepareStatement(String sql, 212 int resultSetType, int resultSetConcurrency) 213 throws SQLException { 214 return conn.prepareStatement(sql, resultSetType, resultSetConcurrency); 215 } 216 @Override 217 public CallableStatement prepareCall(String sql, int resultSetType, 218 int resultSetConcurrency) throws SQLException { 219 return conn.prepareCall(sql, resultSetType, resultSetConcurrency); 220 } 221 @Override 222 public Map<String, Class<?>> getTypeMap() throws SQLException { 223 return conn.getTypeMap(); 224 } 225 @Override 226 public void setTypeMap(Map<String, Class<?>> map) throws SQLException { 227 conn.setTypeMap(map); 228 } 229 @Override 230 public void setHoldability(int holdability) throws SQLException { 231 conn.setHoldability(holdability); 232 } 233 @Override 234 public int getHoldability() throws SQLException { 235 return conn.getHoldability(); 236 } 237 @Override 238 public Savepoint setSavepoint() throws SQLException { 239 return conn.setSavepoint(); 240 } 241 @Override 242 public Savepoint setSavepoint(String name) throws SQLException { 243 return conn.setSavepoint(name); 244 } 245 @Override 246 public void rollback(Savepoint savepoint) throws SQLException { 247 conn.rollback(savepoint); 248 } 249 @Override 250 public void releaseSavepoint(Savepoint savepoint) throws SQLException { 251 conn.releaseSavepoint(savepoint); 252 } 253 @Override 254 public Statement createStatement(int resultSetType, 255 int resultSetConcurrency, int resultSetHoldability) 256 throws SQLException { 257 return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); 258 } 259 @Override 260 public PreparedStatement prepareStatement(String sql, 261 int resultSetType, int resultSetConcurrency, 262 int resultSetHoldability) throws SQLException { 263 return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 264 } 265 @Override 266 public CallableStatement prepareCall(String sql, int resultSetType, 267 int resultSetConcurrency, int resultSetHoldability) 268 throws SQLException { 269 return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 270 } 271 @Override 272 public PreparedStatement prepareStatement(String sql, 273 int autoGeneratedKeys) throws SQLException { 274 return conn.prepareStatement(sql, autoGeneratedKeys); 275 } 276 @Override 277 public PreparedStatement prepareStatement(String sql, 278 int[] columnIndexes) throws SQLException { 279 return conn.prepareStatement(sql, columnIndexes); 280 } 281 @Override 282 public PreparedStatement prepareStatement(String sql, 283 String[] columnNames) throws SQLException { 284 return conn.prepareStatement(sql, columnNames); 285 } 286 @Override 287 public Clob createClob() throws SQLException { 288 return conn.createClob(); 289 } 290 @Override 291 public Blob createBlob() throws SQLException { 292 return conn.createBlob(); 293 } 294 @Override 295 public NClob createNClob() throws SQLException { 296 return conn.createNClob(); 297 } 298 @Override 299 public SQLXML createSQLXML() throws SQLException { 300 return conn.createSQLXML(); 301 } 302 @Override 303 public boolean isValid(int timeout) throws SQLException { 304 return conn.isValid(timeout); 305 } 306 @Override 307 public void setClientInfo(String name, String value) 308 throws SQLClientInfoException { 309 conn.setClientInfo(name, value); 310 } 311 @Override 312 public void setClientInfo(Properties properties) 313 throws SQLClientInfoException { 314 conn.setClientInfo(properties); 315 } 316 @Override 317 public String getClientInfo(String name) throws SQLException { 318 return conn.getClientInfo(name); 319 } 320 @Override 321 public Properties getClientInfo() throws SQLException { 322 return conn.getClientInfo(); 323 } 324 @Override 325 public Array createArrayOf(String typeName, Object[] elements) 326 throws SQLException { 327 return conn.createArrayOf(typeName, elements); 328 } 329 @Override 330 public Struct createStruct(String typeName, Object[] attributes) 331 throws SQLException { 332 return conn.createStruct(typeName, attributes); 333 } 334 @Override 335 public void setSchema(String schema) throws SQLException { 336 } 337 @Override 338 public String getSchema() throws SQLException { 339 return conn.getSchema(); 340 } 341 @Override 342 public void abort(Executor executor) throws SQLException { 343 } 344 @Override 345 public void setNetworkTimeout(Executor executor, int milliseconds) 346 throws SQLException { 347 } 348 @Override 349 public int getNetworkTimeout() throws SQLException { 350 return conn.getNetworkTimeout(); 351 } 352 } 353 }

      3.和之前的相比有哪些改动?

        (1)将数据库连接池的初始化放在了构造方法中。

        (2)连接池中放的是重写的Connection对象。

        (3)没有使用动态代理,效率更高。

        (4)将重写的Connection类放到了连接池类的内部作为内部类使用。

      4.测试代码

    public void testMyDBCPpool() throws SQLException
        {
            MyDBCPpool pool=new MyDBCPpool();
            Connection conn1=pool.getConnection();
            System.out.println(conn1);
            Connection conn2=pool.getConnection();
            System.out.println(conn2);
            Connection conn3=pool.getConnection();
            System.out.println(conn3);
            conn1.close();
            Connection conn4=pool.getConnection();//第四条连接因为拿不到连接而进入等待池中。
            System.out.println(conn4);
        }

      5.运行结果:

    [day16.utils.MyDBCPpool$MyConnection@13f7cd2, day16.utils.MyDBCPpool$MyConnection@11c0042, day16.utils.MyDBCPpool$MyConnection@154fe09]
    分配出一条连接:day16.utils.MyDBCPpool$MyConnection@13f7cd2 剩余2 条连接!
    day16.utils.MyDBCPpool$MyConnection@13f7cd2
    [day16.utils.MyDBCPpool$MyConnection@11c0042, day16.utils.MyDBCPpool$MyConnection@154fe09]
    分配出一条连接:day16.utils.MyDBCPpool$MyConnection@11c0042 剩余1 条连接!
    day16.utils.MyDBCPpool$MyConnection@11c0042
    [day16.utils.MyDBCPpool$MyConnection@154fe09]
    分配出一条连接:day16.utils.MyDBCPpool$MyConnection@154fe09 剩余0 条连接!
    day16.utils.MyDBCPpool$MyConnection@154fe09
    day16.utils.MyDBCPpool$MyConnection@13f7cd2还连接!剩余连接数:1
    [day16.utils.MyDBCPpool$MyConnection@13f7cd2]
    分配出一条连接:day16.utils.MyDBCPpool$MyConnection@13f7cd2 剩余0 条连接!
    day16.utils.MyDBCPpool$MyConnection@13f7cd2

      分析和总结:实际上使用DBCP数据库连接池原理和这基本上差不多,所以该数据库连接池的名字为MyDBCPpool,下面开始进入正题。


     四、DBCP数据库连接池。

      1.需要的jar包

        commons-dbcp2-2.1.jar

        commons-logging-1.2.jar

        commons-pool2-2.4.1.jar

      2.数据源类:

       org.apache.commons.dbcp2.BasicDataSource,但是获取连接的时候使用的是

         org.apache.commons.dbcp2.PoolingDataSource

       Connection类:PoolGuardConnectionWrapper是PoolingDataSource的内部类。

      3.是否回收连接到连接池

       代码追踪:

       PoolGuardConnectionWrapper的close方法:

       

       super.close()调用的并非是Connection类的方法,而是org.apache.commons.dbcp2.DelegatingConnection类的方法。

        

      closeInternal方法

        

      _conn.close()调用的是Connection接口的方法。

        

      可见实际上真的将连接关闭掉了,而非回收到了连接池中。

      4.使用dbcp线程池但是不使用自定义工具类

        4.1不使用配置文件

     1 public void testDBCP() throws SQLException
     2     {
     3         BasicDataSource bds=new BasicDataSource();
     4         bds.setDriverClassName("com.mysql.jdbc.Driver");
     5         bds.setUrl("jdbc:mysql://localhost:3306/bms");
     6         bds.setUsername("root");
     7         bds.setPassword("5a6f38");
     8 //        bds.setInitialSize(3);
     9         bds.setMaxTotal(3);
    10         Connection conn=bds.getConnection();
    11 //        System.out.println(conn.hashCode());
    12         System.out.println(conn);
    13         Connection conn1=bds.getConnection();
    14         System.out.println(conn1);
    15 //        System.out.println(conn1.hashCode());
    16         Connection conn2=bds.getConnection();
    17         System.out.println(conn2);
    18 //        System.out.println(conn2.hashCode());
    19         conn.close();
    20         Connection conn3=bds.getConnection();
    21 //        System.out.println(conn3.hashCode());
    22         System.out.println(conn3);
    23     }

      运行结果:

    25452873, URL=jdbc:mysql://localhost:3306/bms, UserName=root@localhost, MySQL-AB JDBC Driver
    11678023, URL=jdbc:mysql://localhost:3306/bms, UserName=root@localhost, MySQL-AB JDBC Driver
    8058664, URL=jdbc:mysql://localhost:3306/bms, UserName=root@localhost, MySQL-AB JDBC Driver
    15102604, URL=jdbc:mysql://localhost:3306/bms, UserName=root@localhost, MySQL-AB JDBC Driver

      4.2使用配置文件(需要使用一个工厂类BasicDataSourceFactory

    username=root
    password=5a6f38
    url=jdbc:mysql://localhost:3306/test
    driverClassName=com.mysql.jdbc.Driver
    initialSize=3
    maxTotal=3
    #maxTotal的值默认是8,initialSize的值默认也是8
    config_dbcp.properties
     1 public void testAutoConfigMethod()
     2     {
     3         try {
     4             Properties properties=new Properties();
     5             properties.load(Test2.class.getClassLoader().getResourceAsStream("config_dbcp.properties"));
     6             DataSource ds=BasicDataSourceFactory.createDataSource(properties);
     7             Connection conn=ds.getConnection();
     8             System.out.println(conn);
     9             Connection conn1=ds.getConnection();
    10             System.out.println(conn1);
    11             Connection conn2=ds.getConnection();
    12             System.out.println(conn2);
    13             System.out.println("关闭一条连接之后:");
    14             conn.close();
    15             for(int i=0;i<5;i++)
    16             {
    17                 Connection c=ds.getConnection();
    18                 System.out.println(c);
    19             }
    20         } catch (IOException e) {
    21             e.printStackTrace();
    22         } catch (Exception e) {
    23             e.printStackTrace();
    24         }
    25     }

      在这里需要使用一个工厂类:BasicDataSourceFactory

      该工厂类可以根据配置文件创建一个数据源DataSource对象。

      5.定义工具类简化书写过程。

     1 package day16.regular.utils;
     2 
     3 import java.io.IOException;
     4 import java.sql.Connection;
     5 import java.sql.SQLException;
     6 import java.util.Properties;
     7 
     8 import javax.sql.DataSource;
     9 
    10 import org.apache.commons.dbcp2.BasicDataSourceFactory;
    11 
    12 
    13 //使用第三方jar包创建dbcp连接池
    14 public class DataSourceUtils_DBCP {
    15     private DataSourceUtils_DBCP(){}//使用私有修饰构造方法,可以防止创建对象,这样可以确保只有一个DataSource对象
    16     private static DataSource ds;
    17     static
    18     {
    19         Properties properties=new Properties();
    20         try {
    21             properties.load(DataSourceUtils_DBCP.class.getClassLoader().getResourceAsStream("config_dbcp.properties"));
    22             ds=BasicDataSourceFactory.createDataSource(properties);
    23         } catch (IOException e) {
    24             e.printStackTrace();
    25         } catch (Exception e) {
    26             e.printStackTrace();
    27         }
    28     }
    29     public static Connection getConnection()
    30     {
    31         Connection conn=null;
    32         try {
    33             conn=ds.getConnection();
    34         } catch (SQLException e) {
    35             e.printStackTrace();
    36         }
    37         return conn;
    38     }
    39     public static DataSource getDataSource()
    40     {
    41         return ds;
    42     }
    43 }

    五、c3p0数据库连接池。

      1.依赖包下载

      c3p0-0.9.5.jar

      mchange-commons-java-0.2.9.jar

      2.必须使用配置文件,名字必须为:c3p0-config.xml,位置必须在class路径下

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <c3p0-config>
     3     <!-- 默认配置,只可以出现一次 -->
     4     <default-config>
     5         <!-- 连接超时设置30秒 -->
     6         <property name="checkoutTimeout">30000</property>
     7         <!-- 30秒检查一次connection的空闲 -->
     8         <property name="idleConnectionTestPeriod">30</property>
     9         <!--初始化的池大小 -->
    10         <property name="initialPoolSize">2</property>
    11         <!-- 最多的一个connection空闲时间 -->
    12         <property name="maxIdleTime">30</property>
    13         <!-- 最多可以有多少个连接connection -->
    14         <property name="maxPoolSize">10</property>
    15         <!-- 最少的池中有几个连接 -->
    16         <property name="minPoolSize">2</property>
    17         <!-- 批处理的语句-->
    18         <property name="maxStatements">50</property>
    19         <!-- 每次增长几个连接 -->
    20         <property name="acquireIncrement">3</property>
    21         <property name="driverClass">com.mysql.jdbc.Driver</property>
    22         <property name="jdbcUrl">
    23             <![CDATA[jdbc:mysql://10.6.112.200:3306/test?useUnicode=true&characterEncoding=UTF-8]]>
    24         </property>
    25         <property name="user">root</property>
    26         <property name="password">5a6f38</property>
    27     </default-config> 
    28     
    29     <named-config name="namedconfig">
    30         <!-- 连接超时设置30秒 -->
    31         <property name="checkoutTimeout">30000</property>
    32         <!-- 30秒检查一次connection的空闲 -->
    33         <property name="idleConnectionTestPeriod">30</property>
    34         <!--初始化的池大小 -->
    35         <property name="initialPoolSize">2</property>
    36         <!-- 最多的一个connection空闲时间 -->
    37         <property name="maxIdleTime">30</property>
    38         <!-- 最多可以有多少个连接connection -->
    39         <property name="maxPoolSize">2</property>
    40         <!-- 最少的池中有几个连接 -->
    41         <property name="minPoolSize">2</property>
    42         <!-- 批处理的语句-->
    43         <property name="maxStatements">50</property>
    44         <!-- 每次增长几个连接 -->
    45         <property name="acquireIncrement">2</property>
    46         <property name="driverClass">com.mysql.jdbc.Driver</property>
    47         <property name="jdbcUrl">
    48             <![CDATA[jdbc:mysql://10.6.112.200:3306/test?useUnicode=true&characterEncoding=UTF-8]]>
    49         </property>
    50         <property name="user">root</property>
    51         <property name="password">5a6f38</property>
    52     </named-config> 
    53 </c3p0-config>
    c3p0-config.xml

      3.使用的数据源类:com.mchange.v2.c3p0.ComboPooledDataSource

       使用的Connection类:com.mchange.v2.c3p0.impl.NewProxyConnection

      4.自定义工具类包装DataSource以简化书写

     1 package day16.regular.utils;
     2 /**
     3  * 使用c3p0创建的连接池。
     4  */
     5 import java.sql.Connection;
     6 import java.sql.SQLException;
     7 
     8 import javax.sql.DataSource;
     9 
    10 import com.mchange.v2.c3p0.ComboPooledDataSource;
    11 
    12 public class DataSourceUtils_C3P0 {
    13     private static DataSource ds=null;
    14     static{
    15         ds=new ComboPooledDataSource("namedconfig");
    16     }
    17     public static Connection getConnection(){
    18         Connection conn=null;
    19         try {
    20             conn=ds.getConnection();
    21         } catch (SQLException e) {
    22             e.printStackTrace();
    23         }
    24         return conn;
    25     }
    26     public static DataSource getDataSource(){
    27         return ds;
    28     }
    29 }

      5.测试代码

      假设数据库连接池中最多只能有两条连接。

     1 public void testC() throws SQLException
     2     {
          private static DataSource ds=DataSourceUtils_C3P0.getDataSource();
    3 Connection conn=ds.getConnection(); 4 // NewProxyConnection a=null; 5 System.out.println(conn); 6 Connection conn1=ds.getConnection(); 7 System.out.println(conn1); 8 9 conn1.close(); 10 Connection conn2=ds.getConnection(); 11 System.out.println(conn2); 12 }

      6.运行结果:

    连接池初始化信息略。
    com.mchange.v2.c3p0.impl.NewProxyConnection@116d7bd [wrapping: com.mysql.jdbc.JDBC4Connection@ade3e9]
    com.mchange.v2.c3p0.impl.NewProxyConnection@3337df [wrapping: com.mysql.jdbc.JDBC4Connection@9920f6]
    com.mchange.v2.c3p0.impl.NewProxyConnection@1548499 [wrapping: com.mysql.jdbc.JDBC4Connection@9920f6]

      7.c3p0总结。

        (1)c3p0连接池中存放的是标准的Connection对象(实际上是JDBC4Connection对象),在分配的时候再对其进行包装。

        (2)调用close方法将会销毁NewProxyConnection对象,NewProxyConnection是Connection(JDBC4Connection)的包装类。

        (3)调用close方法不会销毁连接池中的对象。

      也就是说c3p0的管理方式类似于卖蛋糕,平时蛋糕放在柜台中,当客人明确了想要买某个蛋糕之后服务人员才对其进行包装。

  • 相关阅读:
    Android Developers:在命令行构建和运行
    pjsip视频通信开发(上层应用)之数字键盘的制作
    Oracle使用goldengate分别向Oracle和mysql双路的单向复制
    js数组的操作
    goldengate的HANDLECOLLISIONS参数
    SQL注入之导出WebShell
    GNURADIO简单运用
    利用Teensy进行EM410x卡模拟以及暴力破解EM410X类门禁系统可行性猜想
    Discuz! 6.x/7.x 版本 前台任意代码执行漏洞
    python之web路径扫描工具
  • 原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4678518.html
Copyright © 2011-2022 走看看