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 }

【运行结果】:

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

如上所示,颜色相同的是相同的连接,可以看出实现了连接的复用。

数据库中通常存在最大的连接数,如果超过最大连接数可能导致数据库崩溃,需要重启数据库。因此,需要对连接数量做控制,改进代码如下:

 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 }

【运行结果】:

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

[email protected]

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)

时间: 2024-08-06 03:39:32

JDBC学习笔记(17):连接池的相关文章

【转】JDBC学习笔记(8)——数据库连接池(dbcp&amp;C3P0)

转自:http://www.cnblogs.com/ysw-go/ JDBC数据库连接池的必要性 一.在使用开发基于数据库的web程序时,传统的模式基本是按一下步骤: 1)在主程序(如servlet/beans)中建立数据库连接 2)进行sql操作 3)断开数据库连接 二.这种模式开发,存在的问题: 1)普通的JDBC数据库连接使用DriverManager来获取,每次向数据库建立连接的时候都要将Connection加载进内存中,再验证用户名和密码(得花费0.05s~1s的时间).需要数据库连接

java学习笔记—c3p0连接池与元数据分析(42)

第一步:导入c3p0包 第二步:在classpath目录下,创建一个c3p0-config.xml <?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <!-- 默认配置,只可以出现一次 --> <default-config> <!-- 连接超时设置30秒 --> <property name="checkoutTimeout"

JDBC学习笔记(一)

public static void main(String[] args) { ResultSet rs = null; Statement stmt = null; Connection conn = null; try { /** * 1.加载JDBC驱动程序: * 加载目标数据库驱动到JVM * 成功加载后,会将Driver类的实例注册到DriverManager类 * oracle-Driver:oracle.jdbc.driver.OracleDriver * MySQL-Drive

Oracle 学习笔记 17 -- 异常处理(PL/SQL)

程序在执行过程中出现异常是正常的,在程序的编写过程中出现异常也是不可避免的.但是要有相应的异常处理的机 制,来保证程序的正常执行.PL/SQL程序执行过程中出现的错误,称为异常.一个优秀的程序都应该能够正确处理 各种出错的情况,并尽可能的从错误中恢复.PL/SQL提供了异常处理机制. 概念: 异常处理(exception)是用来处理正常执行过程中未预料的事件,程序块的异常处理定义的错误和自定义的错误, 由于PL/SQL程序块一旦产生异常而没有指出如何处理时,程序就会异常的终止. 有三种类型的错误

ADO.NET学习笔记之连接字符串

ADO.NET 2.0学习笔记之连接字符串 刚刚入门不久,想什么学习下dot net平台,就先从数据访问入手吧,从今天开始认真学习ado.net 2.0,为将来发展做好坚实基础. 连接字符串 SQL Client .net数据提供程序在连接到数据库时极其灵活,它提供了多种用以生成连接字符串的方式.可以使用关键字,例如“Data Sourse”.“Initial Catalog”,也可以使用"Server".“Database”等旧术语. 下面是两个例子,用于连接到SqlServer数据

python基础教程_学习笔记17:标准库:一些最爱——time

标准库:一些最爱 time time模块所包含的函数能够实现以下功能: 获取当前时间.操作系统时间和日期.从字符串读取时间以及格式化时间为字符串. 日期可以用实数(从"新纪元"的1月1日0点开始计算到现在的秒数,新纪元是一个与平台相关的年份,对unix来说是1970年),或者是包含有9个整数的元组. 日期元组的字段含义 如元组: (2008,1,21,12,2,56,0,21,0) 表示2008年1月21日12时2分56秒,星期一,且是当年的第21天(无夏令时). 索引 字段 值 0

Ext.Net学习笔记17:Ext.Net GridPanel Selection

Ext.Net学习笔记17:Ext.Net GridPanel Selection 接下来是Ext.Net的GridPanel的另外一个功能:选择. 我们在GridPanel最开始的用法中已经见识过如何使用选择功能,今天我们这片笔记将更加详细的介绍Ext.Net GridPanel的Selection功能. Ext.Net GridPanel Selection包括三种: RowSelectionModel:行选择模型 CheckboxSelectionModel:带有复选框的行选择模型 Cel

C++学习笔记17,构造函数体内初始化数据成员与构造函数初始化器的区别(一)

在构造体内初始化数据成员是最常见的方法. 例如: #include <iostream> using namespace std; class A { private: int i; string s; public: A(int ii,string ss){ //在构造函数体内初始化数据成员 i=ii; s=ss; cout<<"ctor:i="<<i<<",s="<<s<<endl; } /

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;