JDBC学习笔记(17):连接池

为了提高效率,在开始时创建多个连接,在需要的时候直接获取连接,使用完毕放回连接池中。
 
创建一个包含5个连接的连接池:
 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 MyDataSource {
 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 LinkedList<Connection> connectionsPool = new LinkedList<>();
12     
13     public MyDataSource() {
14         try {
15             // 创建 5 个连接
16             for (int i = 0; i < 5; i++)
17                 this.connectionsPool.addLast(this.createConnection());
18         } catch (SQLException e) {
19             throw new ExceptionInInitializerError(e);
20         }
21     }
22     
23     private Connection createConnection() throws SQLException {
24         return DriverManager.getConnection(url, user, password);
25     }
26     
27     public void free(Connection conn) {
28         // 释放一个连接,将它放回连接池
29         this.connectionsPool.addLast(conn);
30     }
31     
32     public Connection getConnection() {
33         // 从连接池中获取一个连接
34         return this.connectionsPool.removeFirst();
35     }
36 }

连接池的使用:

 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 public class JdbcUtils {
 7     private static MyDataSource myDataSource = null;
 8     
 9     private JdbcUtils() {
10     }
11     
12     static {
13         try {
14             // 将注册驱动放在静态代码块中只需执行一次
15             Class.forName("com.mysql.jdbc.Driver");
16             myDataSource = new MyDataSource();
17         } catch(ClassNotFoundException e) {
18             throw new ExceptionInInitializerError(e);
19         } 
20     }
21     
22     public static Connection getConnection() throws SQLException {
23 //        return DriverManager.getConnection(url, user, password);
24         // 当需要连接的时候,不再创建,而是从连接池中获取
25         return myDataSource.getConnection();
26     }
27     
28     public static void close(ResultSet rs, Statement stmt, Connection conn) {
29         try {
30             if (rs != null) {
31                 rs.close();
32             }
33         } catch (SQLException e) {
34             e.printStackTrace();
35         } finally {
36             try {
37                 if (stmt != null) {
38                     stmt.close();
39                 }
40             } catch (SQLException e) {
41                 e.printStackTrace();
42             } finally {
43                 if (conn != null) {
44                     try {
45                         //conn.close();
46                         // 将连接放回连接池,而不是关闭连接
47                         myDataSource.free(conn);
48                     } catch (Exception e) {
49                         e.printStackTrace();
50                     }
51                 }
52             }
53         }
54     }
55 }

测试连接池:

 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         //test();
10 //        template();
11         for (int i = 0; i < 10; i++) {
12             Connection conn = JdbcUtils.getConnection();
13             System.out.println(conn);
14             JdbcUtils.close(null, null, conn);
15         }
16     }
17 }
【运行结果】:
com.mysql.jdbc.JDBC4Connection@43d9349c
com.mysql.jdbc.JDBC4Connection@690d1090
com.mysql.jdbc.JDBC4Connection@58ba93d1
com.mysql.jdbc.JDBC4Connection@413eabd9
com.mysql.jdbc.JDBC4Connection@79845505
com.mysql.jdbc.JDBC4Connection@43d9349c
com.mysql.jdbc.JDBC4Connection@690d1090
com.mysql.jdbc.JDBC4Connection@58ba93d1
com.mysql.jdbc.JDBC4Connection@413eabd9
com.mysql.jdbc.JDBC4Connection@79845505  
如上所示,颜色相同的是相同的连接,可以看出实现了连接的复用。
 
 
数据库中通常存在最大的连接数,如果超过最大连接数可能导致数据库崩溃,需要重启数据库。因此,需要对连接数量做控制,改进代码如下:
 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 MyDataSource {
 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     private LinkedList<Connection> connectionsPool = new LinkedList<>();
16     
17     public MyDataSource() {
18         try {
19             // 创建 5 个连接
20             for (int i = 0; i < initCount; i++) {
21                 this.connectionsPool.addLast(this.createConnection());
22                 this.currentCount++;
23             }
24         } catch (SQLException e) {
25             throw new ExceptionInInitializerError(e);
26         }
27     }
28     
29     private Connection createConnection() throws SQLException {
30         return DriverManager.getConnection(url, user, password);
31     }
32     
33     public void free(Connection conn) {
34         // 释放一个连接,将它放回连接池
35         this.connectionsPool.addLast(conn);
36     }
37     
38     public Connection getConnection() throws SQLException {
39         // 从连接池中获取一个连接
40         synchronized(connectionsPool) {
41             if (this.connectionsPool.size() > 0)
42                 return this.connectionsPool.removeFirst();
43             
44             // 如果连接池中没有连接且当前连接小于最大连接,则创建一个连接
45             if (this.currentCount < maxCount) {
46                 this.currentCount++;
47                 return this.createConnection();
48             }
49             
50             throw new SQLException("已没有连接");
51         }
52     }
53 }

在这种情况下,关闭(其实是放回连接池中)连接依然是重要的,测试超过最大连接数:

 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 < 12; i++) {    //////// 超过最大连接数10
11             Connection conn = JdbcUtils.getConnection();
12             System.out.println(conn);
13             //JdbcUtils.close(null, null, conn);//////没有关闭连接
14         }
15     }
16 }
【运行结果】:
com.mysql.jdbc.JDBC4Connection@79845505
com.mysql.jdbc.JDBC4Connection@5ee9f996
com.mysql.jdbc.JDBC4Connection@53011788
com.mysql.jdbc.JDBC4Connection@6cb00c4a
com.mysql.jdbc.JDBC4Connection@19f70605
com.mysql.jdbc.JDBC4Connection@52636e13
com.mysql.jdbc.JDBC4Connection@74b1896c
com.mysql.jdbc.JDBC4Connection@acf3c39
com.mysql.jdbc.JDBC4Connection@14beb6
com.mysql.jdbc.JDBC4Connection@f0f559e
Exception in thread "main" java.sql.SQLException: 已没有连接
    at com.xxyh.jdbc.MyDataSource.getConnection(MyDataSource.java:52)
    at com.xxyh.jdbc.JdbcUtils.getConnection(JdbcUtils.java:27)
    at com.xxyh.jdbc.Base.main(Base.java:14)

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