数据库连接池

写了个 Java数据库连接池,具备基本的功能点:
  1、对池中活动连接的重用。
  2、池满时的适时等待。
  3、对空闲连接的适时关闭。

  抛砖引玉,走过路过,不吝赐教。

 

DBConnection.java如下:

 1 package db;
 2 
 3 import java.sql.Connection;
 4 import java.util.concurrent.atomic.AtomicBoolean;
 5 
 6 /**
 7  * 封装的连接
 8  * @author Linkwork, [email protected]
 9  * @since 2014年11月01日
10  */
11 public class DBConnection {
12     
13     /**
14      * 原生的连接
15      */
16     private Connection connection = null;
17     
18     /**
19      * 是否空闲
20      */
21     private AtomicBoolean idle = null;
22     
23     /**
24      * 最近一次的空闲开始时间
25      */
26     private volatile long idleStart = 0L;
27     
28     /**
29      * 标识
30      */
31     private int index = -1;
32     
33     /**
34      * 构造函数
35      * @param index 标识
36      * @param connection 连接
37      * @param idle 是否空闲
38      */
39     public DBConnection(int index, Connection connection, boolean idle) {
40         this.index = index;
41         this.connection = connection;
42         this.idle = new AtomicBoolean(idle);
43     }
44     
45     /**
46      * 释放
47      */
48     public void release() {
49         if (this.idle.compareAndSet(false, true)) {
50             this.idleStart = System.currentTimeMillis();
51         }
52     }
53 
54     public Connection getConnection() {
55         return connection;
56     }
57 
58     public AtomicBoolean getIdle() {
59         return idle;
60     }
61     
62     public void setConnection(Connection connection) {
63         this.connection = connection;
64     }
65 
66     public int getIndex() {
67         return index;
68     }
69 
70     public long getIdleStart() {
71         return idleStart;
72     }
73 
74     public void setIdleStart(long idleStart) {
75         this.idleStart = idleStart;
76     }
77     
78 }

 

DBConnectionPool.java如下:

  1 package db;
  2 
  3 import java.sql.Connection;
  4 import java.sql.DriverManager;
  5 import java.sql.SQLException;
  6 import java.util.Vector;
  7 
  8 /**
  9  * 数据库连接池
 10  * @author Linkwork, [email protected]
 11  * @since 2014年11月01日
 12  */
 13 public class DBConnectionPool extends Thread {
 14     
 15     /**
 16      * 容量
 17      */
 18     private volatile int capacity = 1;
 19     
 20     /**
 21      * 驱动
 22      */
 23     private String driver = null;
 24     
 25     /**
 26      * 地址
 27      */
 28     private String url = null;
 29     
 30     /**
 31      * 用户名
 32      */
 33     private String user = null;
 34     
 35     /**
 36      * 密码
 37      */
 38     private String password = null;
 39     
 40     /**
 41      * 等待的轮询间隔
 42      */
 43     private volatile long waitInterval = 50L;
 44     
 45     /**
 46      * 等待的超时时间,默认 2分钟
 47      */
 48     private volatile long waitTimeout = 120000L;
 49     
 50     /**
 51      * 空闲的超时时间,默认 5分钟
 52      */
 53     private volatile long idleTimeout = 300000L;
 54     
 55     /**
 56      * 连接集
 57      */
 58     private Vector<DBConnection> dbconnectionLst = null;
 59     
 60     /**
 61      * 是否正在进行关闭
 62      */
 63     private volatile boolean closing = false;
 64     
 65     /**
 66      * 构造函数
 67      * @param capacity 容量
 68      * @param driver 驱动
 69      * @param url 地址
 70      * @param user 用户名
 71      * @param password 密码
 72      */
 73     public DBConnectionPool(
 74             int capacity,
 75             String driver,
 76             String url,
 77             String user,
 78             String password) {
 79         this.capacity = capacity;
 80         this.driver = driver;
 81         this.url = url;
 82         this.user = user;
 83         this.password = password;
 84         this.dbconnectionLst = new Vector<DBConnection>();
 85     }
 86     
 87     /**
 88      * 获取 DB连接
 89      * @return
 90      */
 91     public DBConnection getDBConnectionQuietly() {
 92         try {
 93             return this.getDBConnection();
 94         } catch (Exception e) {
 95             e.printStackTrace();
 96         }
 97         return null;
 98     }
 99     
100     /**
101      * 获取 DB连接
102      * @return
103      * @throws Exception
104      */
105     public DBConnection getDBConnection() throws Exception {
106         long start = System.currentTimeMillis();
107         // 当不是正在进行关闭
108         while (! this.closing) {
109             // 遍历连接集,获取空闲、可用的连接
110             for (DBConnection dbconnection: this.dbconnectionLst) {
111                 if (dbconnection.getIdle().compareAndSet(true, false)) {
112                     // 若连接未关闭
113                     if (! this.isNullOrClose(dbconnection)) {
114                         return dbconnection;
115                     } else {
116                         if (! this.closing) {
117                             dbconnection.getIdle().set(true);
118                         }
119                     }
120                 }
121             }
122             // 若连接的总数未超出容量,则新建连接
123             if ((this.dbconnectionLst.size() < this.capacity)
124                     && (! this.closing)) {
125                 synchronized (this.dbconnectionLst) {
126                     DBConnection dbconnection = this.createDBConnection(this.dbconnectionLst.size() + 1);
127                     this.dbconnectionLst.add(dbconnection);
128                     return dbconnection;
129                 }
130             } 
131             // 遍历连接集,重用空闲、不可用的连接
132             for (DBConnection dbconnection: this.dbconnectionLst) {
133                 if (dbconnection.getIdle().compareAndSet(true, false)) {
134                     // 若连接已关闭
135                     if ((null == dbconnection.getConnection())
136                             || dbconnection.getConnection().isClosed()) {
137                         Connection connection = this.createConnection();
138                         dbconnection.setConnection(connection);
139                         return dbconnection;
140                     } else if (! this.closing) {
141                         dbconnection.getIdle().set(true);
142                     }
143                 }
144             }
145             // 延迟轮询
146             Thread.sleep(this.waitInterval);
147             long end = System.currentTimeMillis();
148             // 若等待超时
149             if (end - start > this.waitTimeout) {
150                 throw new Exception("ERROR_WAIT_TIMEOUT");
151             }
152             start = end;
153         } // while (! this.closing) {
154         return null;
155     }
156     
157     /**
158      * 关闭连接池中的所有连接
159      * @throws Exception
160      */
161     public void close() {
162         this.closing = true;
163         // 是否已经关闭
164         boolean closed = false;
165         // 当未关闭完成
166         while (! closed) {
167             closed = true;
168             try {
169                 Thread.sleep(this.waitInterval);
170             } catch (Exception e) {
171                 e.printStackTrace();
172                 return;
173             }
174             // 遍历连接集,关闭所有空闲连接
175             for (DBConnection dbconnection: this.dbconnectionLst) {
176                 // 若连接空闲,则关闭该连接,并标记未关闭完成
177                 if (dbconnection.getIdle().compareAndSet(true, false)) {
178                     closed = false;
179                     try {
180                         if (! this.isNullOrClose(dbconnection)) {
181                             dbconnection.getConnection().close();
182                         }
183                     } catch (Exception e) {
184                         e.printStackTrace();
185                     }
186                 }
187             }
188         } // while (true) {
189         System.out.println("has closed all!");
190     }
191 
192     @Override
193     public void run() {
194         // 当不是正在进行关闭
195         while (! this.closing) {
196             try {
197                 // 延迟轮询
198                 Thread.sleep(this.waitInterval);
199                 // 遍历连接集,关闭空闲超时的连接
200                 for (DBConnection dbconnection: this.dbconnectionLst) {
201                     // 若连接空闲,且空闲超时
202                     if (dbconnection.getIdle().get()
203                             && this.idleTimeout(dbconnection)
204                             && dbconnection.getIdle().compareAndSet(true, false)) {
205                         // 若连接空闲超时
206                         if (this.idleTimeout(dbconnection)) {
207                             dbconnection.setIdleStart(0L);
208                             dbconnection.getConnection().close();
209                             System.out.println("【dbconnection-" + dbconnection.getIndex() + "】idle timeout.");
210                         }
211                         if (! this.closing) {
212                             dbconnection.getIdle().set(true);
213                         }
214                     }
215                 }
216             } catch (Exception e) {
217                 e.printStackTrace();
218             }
219         }
220     }
221     
222     public int getCapacity() {
223         return capacity;
224     }
225 
226     public void setCapacity(int capacity) {
227         this.capacity = capacity;
228     }
229 
230     public long getWaitTimeout() {
231         return waitTimeout;
232     }
233 
234     public void setWaitTimeout(long waitTimeout) {
235         this.waitTimeout = waitTimeout;
236     }
237 
238     public long getIdleTimeout() {
239         return idleTimeout;
240     }
241 
242     public void setIdleTimeout(long idleTimeout) {
243         this.idleTimeout = idleTimeout;
244     }
245 
246     public long getWaitInterval() {
247         return waitInterval;
248     }
249 
250     public void setWaitInterval(long waitInterval) {
251         this.waitInterval = waitInterval;
252     }
253 
254     /**
255      * 创建 DB连接
256      * @param index
257      * @return
258      * @throws Exception
259      */
260     private DBConnection createDBConnection(int index) throws Exception {
261         return new DBConnection(index, this.createConnection(), false);
262     }
263     
264     /**
265      * 创建连接
266      * @return
267      * @throws Exception
268      */
269     private Connection createConnection() throws Exception {
270         Class.forName(this.driver);
271         return DriverManager.getConnection(this.url, this.user, this.password);
272     }
273     
274     /**
275      * DB连接是否空闲超时
276      * @param dbconnection
277      * @return
278      */
279     private boolean idleTimeout(DBConnection dbconnection) {
280         return ((dbconnection.getIdleStart() > 0)
281                 && (System.currentTimeMillis() - dbconnection.getIdleStart() > this.idleTimeout));
282     }
283     
284     /**
285      * DB连接是否为空、或已关闭
286      * @param dbconnection
287      * @return
288      * @throws SQLException
289      */
290     private boolean isNullOrClose(DBConnection dbconnection) throws SQLException {
291         return ((null == dbconnection.getConnection())
292                 || dbconnection.getConnection().isClosed());
293     }
294 
295 }

 

DBConnectionPoolTest.java如下

 1 package db;
 2 
 3 import java.sql.PreparedStatement;
 4 import java.text.SimpleDateFormat;
 5 import java.util.Date;
 6 
 7 /**
 8  * 测试:数据库连接池
 9  * @author Linkwork, [email protected]
10  * @since 2014年11月0日
11  */
12 public class DBConnectionPoolTest {
13     
14     public static void main(String[] args) {
15         DBConnectionPool pool = new DBConnectionPool(3, "com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/db", "lw2013qq", "omg2056db4qq");
16         pool.setWaitTimeout(10000L);
17         pool.setIdleTimeout(40L);
18         pool.start();
19         testPool(pool);
20         pool.close();
21     }
22     
23     /**
24      * 测试连接池
25      * @param pool
26      */
27     public static void testPool(DBConnectionPool pool) {
28         DBConnection dbconnection = pool.getDBConnectionQuietly();
29         if (null != dbconnection) {
30             try {
31                 // 创建表
32                 dbconnection.getConnection().prepareStatement("create table if not exists test_pool (tp_value int);").execute();
33                 dbconnection.release();
34                 mockConcurrent(pool);
35                 Thread.sleep(1000);
36                 mockConcurrent(pool);
37                 Thread.sleep(60);
38             } catch (Exception e) {
39                 e.printStackTrace();
40             } finally {
41                 dbconnection.release();
42             }
43         }
44     }
45     
46     /**
47      * 模拟多线程并发访问数据库,并发插入 10行数据
48      * @param pool
49      */
50     public static void mockConcurrent(DBConnectionPool pool) {
51         for (int index = 0; index < 10; ++ index) {
52             final int value = index;
53             Thread thread = new Thread() {
54                 public void run() {
55                     DBConnection dbconnection = pool.getDBConnectionQuietly();
56                     if (null != dbconnection) {
57                         try {
58                             // 插入数据
59                             PreparedStatement statement = dbconnection.getConnection().prepareStatement("insert into test_pool(tp_value) values(?);");
60                             statement.setInt(1, value);
61                             statement.execute();
62                             StringBuffer msg = new StringBuffer();
63                             msg.append("dbconnection index=").append(dbconnection.getIndex())
64                                 .append(", insert=").append(value)
65                                 .append(", time=").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
66                             System.out.println(msg.toString());
67                         } catch (Exception e) {
68                             e.printStackTrace();
69                         } finally {
70                             dbconnection.release();
71                         }
72                     }
73                 }
74             };
75             thread.start();
76         }
77     }
78 
79 }

 

运行 DBConnectionPoolTest.java,控制台输出:

 1 dbconnection index=1, insert=0, time=2014-11-29 11:20:46 901
 2 dbconnection index=2, insert=2, time=2014-11-29 11:20:46 917
 3 dbconnection index=3, insert=8, time=2014-11-29 11:20:46 917
 4 dbconnection index=2, insert=1, time=2014-11-29 11:20:46 960
 5 dbconnection index=1, insert=4, time=2014-11-29 11:20:46 960
 6 dbconnection index=3, insert=6, time=2014-11-29 11:20:46 984
 7 dbconnection index=2, insert=7, time=2014-11-29 11:20:47 008
 8 dbconnection index=1, insert=9, time=2014-11-29 11:20:47 008
 9 【dbconnection-3】idle timeout.
10 dbconnection index=1, insert=3, time=2014-11-29 11:20:47 092
11 dbconnection index=2, insert=5, time=2014-11-29 11:20:47 142
12 【dbconnection-1】idle timeout.
13 【dbconnection-2】idle timeout.
14 dbconnection index=2, insert=1, time=2014-11-29 11:20:47 907
15 dbconnection index=1, insert=0, time=2014-11-29 11:20:47 929
16 dbconnection index=3, insert=3, time=2014-11-29 11:20:47 929
17 dbconnection index=2, insert=4, time=2014-11-29 11:20:47 948
18 dbconnection index=1, insert=5, time=2014-11-29 11:20:47 982
19 dbconnection index=3, insert=8, time=2014-11-29 11:20:47 982
20 has closed all!

 

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