JDBC学习笔记(18):通过代理模式来保持用户关闭连接的习惯

在前面的JdbcUtils包中,在关闭连接的时候使用了conn.close()方法,如果关闭了连接,那么放回连接池中的连接就成为无效的连接,为了规范用户关闭连接的习惯,使用代理模式来将连接放回连接池而又不改变用户的程序:

将JdbcUtils工具包改变回原来的情形:
 1 package com.xxyh.jdbc;
 2 import java.sql.Connection;
 3 import java.sql.ResultSet;
 4 import java.sql.SQLException;
 5 import java.sql.Statement;
 6 import com.xxyh.jdbc.datasource.MyDataSource2;
 7 public class JdbcUtils {
 8     private static MyDataSource2 myDataSource = null;
 9     
10     private JdbcUtils() {
11     }
12     
13     static {
14         try {
15             // 将注册驱动放在静态代码块中只需执行一次
16             Class.forName("com.mysql.jdbc.Driver");
17             myDataSource = new MyDataSource2();
18         } catch(ClassNotFoundException e) {
19             throw new ExceptionInInitializerError(e);
20         } 
21     }
22     
23     public static Connection getConnection() throws SQLException {
24 //        return DriverManager.getConnection(url, user, password);
25         // 当需要连接的时候,不再创建,而是从连接池中获取
26         return myDataSource.getConnection();
27     }
28     
29     public static void close(ResultSet rs, Statement stmt, Connection conn) {
30         try {
31             if (rs != null) {
32                 rs.close();
33             }
34         } catch (SQLException e) {
35             e.printStackTrace();
36         } finally {
37             try {
38                 if (stmt != null) {
39                     stmt.close();
40                 }
41             } catch (SQLException e) {
42                 e.printStackTrace();
43             } finally {
44                 if (conn != null) {
45                     try {
46                         conn.close();    ///////按照常用情形关闭连接
47                         // 将连接放回连接池,而不是关闭连接
48 //                        myDataSource.free(conn);
49                     } catch (Exception e) {
50                         e.printStackTrace();
51                     }
52                 }
53             }
54         }
55     }
56 }

创建自己的连接方式,实现java.sql.Connection接口,截取部分代码:

 1 package com.xxyh.jdbc.datasource;
 2 import java.sql.Array;
 3 import java.sql.Blob;
 4 import java.sql.CallableStatement;
 5 import java.sql.Clob;
 6 import java.sql.Connection;
 7 import java.sql.DatabaseMetaData;
 8 import java.sql.NClob;
 9 import java.sql.PreparedStatement;
10 import java.sql.SQLClientInfoException;
11 import java.sql.SQLException;
12 import java.sql.SQLWarning;
13 import java.sql.SQLXML;
14 import java.sql.Savepoint;
15 import java.sql.Statement;
16 import java.sql.Struct;
17 import java.util.Map;
18 import java.util.Properties;
19 import java.util.concurrent.Executor;
20 public class MyConnection implements Connection{
21     
22     private Connection realConnetion; // 真正的数据库连接,可能来源于MySQL、Oracle、DB2……
23     private MyDataSource2 dataSource;
24     
25     MyConnection(Connection connection, MyDataSource2 dataSource) {
26         this.realConnetion = connection;
27         this.dataSource = dataSource;
28     }
29     
30     @Override
31     public void close() throws SQLException {
32         this.dataSource.connectionsPool.addLast(this);
33     }
34     
35     @Override
36     public void commit() throws SQLException {
37         // TODO Auto-generated method stub
38         this.realConnetion.commit();
39     }
以上只是部分代码,值得注意的是close方法,并不是将连接关闭,而是让它放回连接池。
 
连接池:
 1 package com.xxyh.jdbc.datasource;
 2 import java.sql.Connection;
 3 import java.sql.DriverManager;
 4 import java.sql.SQLException;
 5 import java.util.LinkedList;
 6 public class MyDataSource2 {
 7     private static String url = "jdbc:mysql://localhost:3306/jdbc?generateSimpleParameterMetadata=true";
 8     private static String user = "root";
 9     private static String password = "1234";
10     
11     private static int initCount = 5;    // 初始连接数
12     private static int maxCount = 10;    // 最大连接数
13     private int currentCount = 0;        // 当前连接数
14     
15     ////////包内可见
16     LinkedList<Connection> connectionsPool = new LinkedList<>();
17     
18     public MyDataSource2() {
19         try {
20             // 创建 5 个连接
21             for (int i = 0; i < initCount; i++) {
22                 this.connectionsPool.addLast(this.createConnection());
23                 this.currentCount++;
24             }
25         } catch (SQLException e) {
26             throw new ExceptionInInitializerError(e);
27         }
28     }
29     
30     private Connection createConnection() throws SQLException {
31         Connection realConn = DriverManager.getConnection(url, user, password);
32         MyConnection myConnection = new MyConnection(realConn, this);
33         return myConnection; 
34     }
35     
36     public void free(Connection conn) {
37         // 释放一个连接,将它放回连接池
38         this.connectionsPool.addLast(conn);
39     }
40     
41     public Connection getConnection() throws SQLException {
42         // 从连接池中获取一个连接
43         synchronized(connectionsPool) {
44             if (this.connectionsPool.size() > 0)
45                 return this.connectionsPool.removeFirst();
46             
47             // 如果连接池中没有连接且当前连接小于最大连接,则创建一个连接
48             if (this.currentCount < maxCount) {
49                 this.currentCount++;
50                 return this.createConnection();
51             }
52             
53             throw new SQLException("已没有连接");
54         }
55     }
56 }

测试创建的连接:

 1 package com.xxyh.jdbc;
 2 import java.sql.Connection;
 3 import java.sql.DriverManager;
 4 import java.sql.ResultSet;
 5 import java.sql.SQLException;
 6 import java.sql.Statement;
 7 public class Base {
 8     public static void main(String[] args) throws ClassNotFoundException, SQLException {
 9 
10         for (int i = 0; i < 5; i++) {
11             Connection conn = JdbcUtils.getConnection();
12             System.out.println(conn);
13             JdbcUtils.close(null, null, conn);
14         }
15     }
16 }
【运行结果】:
com.xxyh.jdbc.datasource.MyConnection@59ea632e
com.xxyh.jdbc.datasource.MyConnection@2b158f20
com.xxyh.jdbc.datasource.MyConnection@146793f9
com.xxyh.jdbc.datasource.MyConnection@1c23cae6
com.xxyh.jdbc.datasource.MyConnection@71ddd078 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。