Skip to content

Commit 4eebcbf

Browse files
committed
implemented ConnectionPool
1 parent c2c0215 commit 4eebcbf

7 files changed

Lines changed: 261 additions & 27 deletions

File tree

bin/dbconfig.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ USERNAME=root
1010
#database pass
1111
#USERPWD=P@ssw0rd
1212
USERPWD=123456
13-
DIALECT=MYSQL
13+
DIALECT=MYSQL
14+
USEPOOL=true

src/dbconfig.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ USERNAME=root
1010
#database pass
1111
#USERPWD=P@ssw0rd
1212
USERPWD=123456
13-
DIALECT=MYSQL
13+
DIALECT=MYSQL
14+
USEPOOL=true

src/openthinks/libs/sql/dao/pool/ConnectionPool.java

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package openthinks.libs.sql.dao.pool;
2727

2828
import java.sql.Connection;
29+
import java.sql.SQLException;
2930

3031
/**
3132
* The pool for {@link Connection}
@@ -34,38 +35,32 @@
3435
*/
3536
public interface ConnectionPool {
3637

38+
String MAX_ACTIVE = "";
39+
3740
/**
3841
* request a {@link Connection}, maybe it is a new or it is already existed
3942
* @return Connection
43+
* @throws ClassNotFoundException
44+
* @throws SQLException
4045
*/
41-
Connection request();
46+
Connection request() throws ClassNotFoundException, SQLException;
4247

4348
/**
4449
* recycle the {@link Connection}s
4550
* @param conns Connection[]
4651
*/
4752
void recycle(Connection... conns);
48-
49-
/**
50-
* really close the given {@link Connection}s
51-
* @param conns Connection[]
52-
*/
53-
void destroy(Connection... conns);
54-
53+
5554
/**
56-
* current count of active {@link Connection} in pool
55+
* current count of free {@link Connection} in pool
5756
* @return Integer
5857
*/
5958
int size();
60-
61-
/**
62-
* the capacity or max count of the pool for holding {@link Connection}
63-
* @return Integer
64-
*/
65-
int capacity();
66-
59+
6760
/**
68-
* really close all holding {@link Connection}s
61+
* really close all holding {@link Connection}s, and reject other actions
6962
*/
70-
void destroyAll();
63+
void shutdown();
64+
65+
boolean isShutdown();
7166
}

src/openthinks/libs/sql/dao/pool/ConnectionPoolManager.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,38 @@
2525
*/
2626
package openthinks.libs.sql.dao.pool;
2727

28+
import java.util.concurrent.locks.Lock;
29+
import java.util.concurrent.locks.ReentrantLock;
30+
31+
import openthinks.libs.sql.dao.pool.impl.SimpleConnectionPool;
2832
import openthinks.libs.sql.lang.Configurator;
33+
import openthinks.libs.utilities.Checker;
2934

3035
/**
3136
* The management of {@link ConnectionPool}
3237
* @author dailey.yet@outlook.com
3338
*
3439
*/
3540
public class ConnectionPoolManager {
41+
private static ConnectionPool singletonPoolInstance;
42+
private static Lock lock = new ReentrantLock();
3643

3744
/**
3845
* @param configurator Configurator
3946
* @return ConnectionPool
4047
*/
4148
public static ConnectionPool getInstance(Configurator configurator) {
42-
// TODO Auto-generated method stub
43-
return null;
49+
Checker.require(configurator).notNull();
50+
if (!configurator.isUsePool())
51+
throw new IllegalArgumentException("Current configuration for database without using pool.");
52+
lock.lock();
53+
try {
54+
if (singletonPoolInstance == null || singletonPoolInstance.isShutdown()) {
55+
singletonPoolInstance = new SimpleConnectionPool(configurator);
56+
}
57+
} finally {
58+
lock.unlock();
59+
}
60+
return singletonPoolInstance;
4461
}
45-
4662
}
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*
19+
* @Title: SimpleConnectionPool.java
20+
* @Package openthinks.libs.sql.dao.pool.impl
21+
* @author dailey.yet@outlook.com
22+
* @date Jul 31, 2015
23+
* @version V1.0
24+
*/
25+
package openthinks.libs.sql.dao.pool.impl;
26+
27+
import java.sql.Connection;
28+
import java.sql.DriverManager;
29+
import java.sql.SQLException;
30+
import java.util.Arrays;
31+
import java.util.concurrent.ConcurrentLinkedQueue;
32+
import java.util.concurrent.atomic.AtomicBoolean;
33+
import java.util.concurrent.atomic.AtomicInteger;
34+
import java.util.concurrent.locks.Lock;
35+
import java.util.concurrent.locks.ReentrantLock;
36+
37+
import openthinks.libs.sql.dao.pool.ConnectionPool;
38+
import openthinks.libs.sql.lang.Configurator;
39+
40+
import org.apache.log4j.Logger;
41+
42+
/**
43+
* Simple and default implementation of {@link ConnectionPool}
44+
* @author dailey.yet@outlook.com
45+
*
46+
*/
47+
public class SimpleConnectionPool implements ConnectionPool {
48+
private static final Object MAX_IDLE = null;
49+
private final ConcurrentLinkedQueue<Connection> connectionQueue;
50+
private final Configurator configurator;
51+
private final Lock lock;
52+
private final AtomicInteger freeCount = new AtomicInteger(0);
53+
private final AtomicInteger activeCount = new AtomicInteger(0);
54+
private final AtomicBoolean rejectAction = new AtomicBoolean(false);
55+
private final Logger logger = Logger.getLogger(SimpleConnectionPool.class);
56+
57+
/**
58+
*
59+
*/
60+
public SimpleConnectionPool(Configurator configurator) {
61+
this.connectionQueue = new ConcurrentLinkedQueue<Connection>();
62+
this.lock = new ReentrantLock();
63+
this.configurator = configurator;
64+
}
65+
66+
/* (non-Javadoc)
67+
* @see openthinks.libs.sql.dao.pool.ConnectionPool#request()
68+
*/
69+
@Override
70+
public Connection request() throws ClassNotFoundException, SQLException {
71+
if (rejectAction.get())
72+
throw new IllegalStateException("This pool has been shutdown.");
73+
lock.lock();
74+
try {
75+
Connection conn = connectionQueue.poll();
76+
if (conn == null) {//no free connection, create new connection
77+
conn = createConnection();
78+
} else if (conn.isClosed()) {//process the closed connection, and recreate a new connection
79+
destroy(conn);
80+
conn = createConnection();
81+
} else {//directly get connections from free side
82+
freeCount.decrementAndGet();
83+
}
84+
return conn;
85+
} finally {
86+
lock.unlock();
87+
}
88+
}
89+
90+
/**
91+
* Create a new {@link Connection}
92+
* @return Connection
93+
* @throws IllegalStateException
94+
* @throws ClassNotFoundException
95+
* @throws SQLException
96+
*/
97+
protected Connection createConnection() throws IllegalStateException, ClassNotFoundException, SQLException {
98+
Connection conn;
99+
if (activeCount.get() >= this.maxActive())
100+
throw new IllegalStateException("Reached the maximum number of database connections in pool.");
101+
Class.forName(configurator.getDriver());
102+
conn = DriverManager
103+
.getConnection(configurator.getUrl(), configurator.getUserName(), configurator.getUserPwd());
104+
activeCount.incrementAndGet();
105+
return conn;
106+
}
107+
108+
/* (non-Javadoc)
109+
* @see openthinks.libs.sql.dao.pool.ConnectionPool#recycle(java.sql.Connection[])
110+
*/
111+
@Override
112+
public void recycle(Connection... conns) {
113+
if (conns == null || conns.length == 0)
114+
return;
115+
if (rejectAction.get())
116+
throw new IllegalStateException("This pool has been shutdown.");
117+
lock.lock();
118+
try {
119+
boolean result = connectionQueue.addAll(Arrays.asList(conns));
120+
if (result) {
121+
freeCount.addAndGet(conns.length);
122+
}
123+
} finally {
124+
lock.unlock();
125+
}
126+
127+
}
128+
129+
void destroy(Connection... conns) {
130+
if (conns == null || conns.length == 0)
131+
return;
132+
for (Connection conn : conns) {
133+
try {
134+
if (conn != null && !conn.isClosed()) {
135+
conn.close();
136+
}
137+
} catch (SQLException e) {
138+
logger.error("Database access error occurs", e);
139+
continue;
140+
}
141+
lock.lock();
142+
try {
143+
boolean changed = this.connectionQueue.remove(conn);
144+
if (changed)
145+
freeCount.decrementAndGet();
146+
activeCount.decrementAndGet();
147+
} finally {
148+
lock.unlock();
149+
}
150+
}
151+
152+
}
153+
154+
/* (non-Javadoc)
155+
* @see openthinks.libs.sql.dao.pool.ConnectionPool#size()
156+
*/
157+
@Override
158+
public int size() {
159+
return activeCount.get();
160+
}
161+
162+
public int maxActive() {
163+
String maxActive = (String) this.configurator.get(MAX_ACTIVE);
164+
return maxActive == null ? Integer.MAX_VALUE : Integer.valueOf(maxActive);
165+
}
166+
167+
public int maxIdle() {
168+
String maxIdle = (String) this.configurator.get(MAX_IDLE);
169+
return maxIdle == null ? Integer.MAX_VALUE : Integer.valueOf(maxIdle);
170+
}
171+
172+
/* (non-Javadoc)
173+
* @see openthinks.libs.sql.dao.pool.ConnectionPool#shutdown()
174+
*/
175+
@Override
176+
public void shutdown() {
177+
rejectAction.compareAndSet(false, true);
178+
Connection conn = this.connectionQueue.poll();
179+
while (conn != null) {
180+
try {
181+
if (!conn.isClosed()) {
182+
conn.close();
183+
}
184+
} catch (SQLException e) {
185+
logger.error("Database access error occurs", e);
186+
continue;
187+
}
188+
lock.lock();
189+
try {
190+
boolean changed = this.connectionQueue.remove(conn);
191+
if (changed)
192+
freeCount.decrementAndGet();
193+
activeCount.decrementAndGet();
194+
} finally {
195+
lock.unlock();
196+
}
197+
conn = this.connectionQueue.poll();
198+
}
199+
}
200+
201+
public boolean isShutdown() {
202+
return rejectAction.get();
203+
}
204+
205+
}

src/openthinks/libs/sql/dhibernate/support/SessionDaoImpl.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public SessionDaoImpl() {
5252
public Connection getConn() throws ClassNotFoundException, SQLException {
5353
lock.lock();
5454
try {
55-
if (connection == null)
55+
if (connection == null || connection.isClosed())
5656
connection = ConnectionManager.getConnection(getConfigurator());
5757
return connection;
5858
} finally {
@@ -83,10 +83,9 @@ public void closeConnection(Connection conn) {
8383
try {
8484
if (isAutoClose())
8585
super.closeConnection(conn);
86-
if (isUsePool()) {
86+
if (isUsePool())
8787
ConnectionManager.closeConnection(getConfigurator(), conn);
88-
this.connection = null;
89-
}
88+
this.connection = null;
9089
} finally {
9190
lock.unlock();
9291
}

test/openthinks/libs/sql/SaveTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,21 @@ public void testUpdate() {
6060
session.close();
6161
}
6262

63+
public static void main(String[] args) {
64+
Session session = SessionFactory.getSession();
65+
session.list(Message.class);
66+
session.close();
67+
68+
session = SessionFactory.getSession();
69+
session.list(Message.class);
70+
session.close();
71+
72+
session = SessionFactory.getSession();
73+
session.list(Message.class);
74+
session.close();
75+
76+
session = SessionFactory.getSession();
77+
session.list(Message.class);
78+
session.close();
79+
}
6380
}

0 commit comments

Comments
 (0)