JAVA数据库连接池实现
博客分类:
• 数据库连接池
JAVA数据库连接池连接池原理连接池实现JAVA连接池
连接池的管理用了了享元模式,这里对连接池进行简单设计。
一、设计思路
1.连接池配置属性DBbean:里面存放可以配置的一些属性
2.连接池接口IConnectionPool:里面定义一些基本的获取连接的一些方法
3.接口实现ConnectionPool:对上面操作进行实现,并加入一些其他方法
4.连接池管理ConnectionPoolManager:管理所有的不同的连接池,所有的连接都能通过这里进行获得连接
5.另外还有几个测试类,和连接信息模拟的类,这里就不进行xml 和配置文件信息的读取了
Java代码
1. package pool;
2. /**
3. * 这是外部可以配置的连接池属性
4. * 可以允许外部配置,拥有默认值
5. * @author Ran
6. *
7. */
8. public class DBbean {
9. // 连接池属性
10. private String driverName;
11. private String url;
12. private String userName;
13. private String password;
14. // 连接池名字
15. private String poolName;
16. private int minConnections = 1; // 空闲池,最小连接数
17. private int maxConnections = 10; // 空闲池,最大连接数
18.
19. private int initConnections = 5;// 初始化连接数
20.
21. private long connTimeOut = 1000;// 重复获得连接的频率
22.
23. private int maxActiveConnections = 100;// 最大允许的连接数,和数据库对应
24.
25. private long connectionTimeOut = 1000*60*20;// 连接超时时间,默认20分钟
26.
27. private boolean isCurrentConnection = true; // 是否获得当前连接,默认true
28.
29. private boolean isCheakPool = true; // 是否定时检查连接池
30. private long lazyCheck = 1000*60*60;// 延迟多少时间后开始 检查
31. private long periodCheck = 1000*60*60;// 检查频率
32.
33.
34.
35. public DBbean(String driverName, String url, String userName,
36. String password, String poolName) {
37. super();
38. this.driverName = driverName;
39. this.url = url;
40. this.userName = userName;
41. this.password = password;
42. this.poolName = poolName;
43. }
44. public DBbean() {
45. }
46. public String getDriverName() {
47. if(driverName == null){
48. driverName = this.getDriverName()+"_"+this.getUrl();
49. }
50. return driverName;
51. }
52. public void setDriverName(String driverName) {
53. this.driverName = driverName;
54. }
55. public String getUrl() {
56. return url;
57. }
58. public void setUrl(String url) {
59. this.url = url;
60. }
61. public String getUserName() {
62. return userName;
63. }
64. public void setUserName(String userName) {
65. this.userName = userName;
66. }
67. public String getPassword() {
68. return password;
69. }
70. public void setPassword(String password) {
71. this.password = password;
72. }
73. public String getPoolName() {
74. return poolName;
75. }
76. public void setPoolName(String poolName) {
77. this.poolName = poolName;
78. }
79. public int getMinConnections() {
80. return minConnections;
81. }
82. public void setMinConnections(int minConnections) {
83. this.minConnections = minConnections;
84. }
85. public int getMaxConnections() {
86. return maxConnections;
87. }
88. public void setMaxConnections(int maxConnections) {
89. this.maxConnections = maxConnections;
90. }
91. public int getInitConnections() {
92. return initConnections;
93. }
94. public void setInitConnections(int initConnections) {
95. this.initConnections = initConnections;
96. }
97.
98. public int getMaxActiveConnections() {
99. return maxActiveConnections;
100. }
101. public void setMaxActiveConnections(int maxActiveConnections) {
102. this.maxActiveConnections = maxActiveConnections;
103. }
104. public long getConnTimeOut() {
105. return connTimeOut;
106. }
107. public void setConnTimeOut(long connTimeOut) {
108. this.connTimeOut = connTimeOut;
109. }
110. public long getConnectionTimeOut() {
111. return connectionTimeOut;
112. }
113. public void setConnectionTimeOut(long connectionTimeOut) {
114. this.connectionTimeOut = connectionTimeOut;
115. }
116. public boolean isCurrentConnection() {
117. return isCurrentConnection;
118. }
119. public void setCurrentConnection(boolean isCurrentConnection) {
120. this.isCurrentConnection = isCurrentConnection;
121. }
122. public long getLazyCheck() {
123. return lazyCheck;
124. }
125. public void setLazyCheck(long lazyCheck) {
126. this.lazyCheck = lazyCheck;
127. }
128. public long getPeriodCheck() {
129. return periodCheck;
130. }
131. public void setPeriodCheck(long periodCheck) {
132. this.periodCheck = periodCheck;
133. }
134. public boolean isCheakPool() {
135. return isCheakPool;
136. }
137. public void setCheakPool(boolean isCheakPool) {
138. this.isCheakPool = isCheakPool;
139. }
140.
141.
142.
143. }
Java代码
1. package pool;
2.
3. import java.sql.Connection;
4. import java.sql.SQLException;
5.
6. public interface IConnectionPool {
7. // 获得连接
8. public Connection getConnection();
9. // 获得当前连接
10. public Connection getCurrentConnecton();
11. // 回收连接
12. public void releaseConn(Connection conn) throws SQLException;
13. // 销毁清空
14. public void destroy();
15. // 连接池是活动状态
16. public boolean isActive();
17. // 定时器,检查连接池
18. public void cheackPool();
19. }
Java代码
1. package pool;
2.
3. import java.sql.Connection;
4. import java.sql.DriverManager;
5. import java.sql.SQLException;
6. import java.util.List;
7. import java.util.Timer;
8. import java.util.TimerTask;
9. import java.util.Vector;
10.
11. public class ConnectionPool implements IConnectionPool {
12. // 连接池配置属性
13. private DBbean dbBean;
14. private boolean isActive = false; // 连接池活动状态
15. private int contActive = 0;// 记录创建的总的连接数
16.
17. // 空闲连接
18. private List freeConnection = new Vector();
19. // 活动连接
20. private List activeConnection = new Vector();
21. // 将线程和连接绑定,保证事务能统一执行
22. private static ThreadLocal threadLocal = new ThreadLocal();
23.
24. public ConnectionPool(DBbean dbBean) {
25. super();
26. this.dbBean = dbBean;
27. init();
28. cheackPool();
29. }
30.
31. // 初始化
32. public void init() {
33. try {
34. Class.forName(dbBean.getDriverName());
35. for (int i = 0; i < dbBean.getInitConnections(); i++) {
36. Connection conn;
37. conn = newConnection();
38. // 初始化最小连接数
39. if (conn != null) {
40. freeConnection.add(conn);
41. contActive++;
42. }
43. }
44. isActive = true;
45. } catch (ClassNotFoundException e) {
46. e.printStackTrace();
47. } catch (SQLException e) {
48. e.printStackTrace();
49. }
50. }
51.
52. // 获得当前连接
53. public Connection getCurrentConnecton(){
54. // 默认线程里面取
55. Connection conn = threadLocal.get();
56. if(!isValid(conn)){
57. conn = getConnection();
58. }
59. return conn;
60. }
61.
62. // 获得连接
63. public synchronized Connection getConnection() {
64. Connection conn = null;
65. try {
66. // 判断是否超过最大连接数限制
67. if(contActive < this.dbBean.getMaxActiveConnections()){
68. if (freeConnection.size() > 0) {
69. conn = freeConnection.get(0);
70. if (conn != null) {
71. threadLocal.set(conn);
72. }
73. freeConnection.remove(0);
74. } else {
75. conn = newConnection();
76. }
77.
78. }else{
79. // 继续获得连接,直到从新获得连接
80. wait(this.dbBean.getConnTimeOut());
81. conn = getConnection();
82. }
83. if (isValid(conn)) {
84. activeConnection.add(conn);
85. contActive ++;
86. }
87. } catch (SQLException e) {
88. e.printStackTrace();
89. } catch (ClassNotFoundException e) {
90. e.printStackTrace();
91. } catch (InterruptedException e) {
92. e.printStackTrace();
93. }
94. return conn;
95. }
96.
97. // 获得新连接
98. private synchronized Connection newConnection()
99. throws ClassNotFoundException, SQLException {
100. Connection conn = null;
101. if (dbBean != null) {
102. Class.forName(dbBean.getDriverName());
103. conn = DriverManager.getConnection(dbBean.getUrl(),
104. dbBean.getUserName(), dbBean.getPassword());
105. }
106. return conn;
107. }
108.
109. // 释放连接
110. public synchronized void releaseConn(Connection conn) throws SQLException {
111. if (isValid(conn)&& !(freeConnection.size() > dbBean.getMaxConnections())) {
112. freeConnection.add(conn);
113. activeConnection.remove(conn);
114. contActive --;
115. threadLocal.remove();
116. // 唤醒所有正待等待的线程,去抢连接
117. notifyAll();
118. }
119. }
120.
121. // 判断连接是否可用
122. private boolean isValid(Connection conn) {
123. try {
124. if (conn == null || conn.isClosed()) {
125. return false;
126. }
127. } catch (SQLException e) {
128. e.printStackTrace();
129. }
130. return true;
131. }
132.
133. // 销毁连接池
134. public synchronized void destroy() {
135. for (Connection conn : freeConnection) {
136. try {
137. if (isValid(conn)) {
138. conn.close();
139. }
140. } catch (SQLException e) {
141. e.printStackTrace();
142. }
143. }
144. for (Connection conn : activeConnection) {
145. try {
146. if (isValid(conn)) {
147. conn.close();
148. }
149. } catch (SQLException e) {
150. e.printStackTrace();
151. }
152. }
153. isActive = false;
154. contActive = 0;
155. }
156.
157. // 连接池状态
158. @Override
159. public boolean isActive() {
160. return isActive;
161. }
162.
163. // 定时检查连接池情况
164. @Override
165. public void cheackPool() {
166. if(dbBean.isCheakPool()){
167. new Timer().schedule(new TimerTask() {
168. @Override
169. public void run() {
170. // 1.对线程里面的连接状态
171. // 2.连接池最小 最大连接数
172. // 3.其他状态进行检查,因为这里还需要写几个线程管理的类,暂时就不添加了
173. System.out.println("空线池连接数:"+freeConnection.size());
174. System.out.println("活动连接数::"+activeConnection.size());
175. System.out.println("总的连接数:"+contActive);
176. }
177. },dbBean.getLazyCheck(),dbBean.getPeriodCheck());
178. }
179. }
180. }
Java代码
1. package pool;
2.
3. import java.sql.Connection;
4. import java.sql.SQLException;
5. import java.util.Hashtable;
6. /**
7. * 连接管理类
8. * @author Ran
9. *
10. */
11. public class ConnectionPoolManager {
12.
13.
14. // 连接池存放
15. public Hashtable
1. package pool;
2.
3. import java.sql.Connection;
4. /**
5. * 模拟线程启动,去获得连接
6. * @author Ran
7. *
8. */
9. public class ThreadConnection implements Runnable{
10. private IConnectionPool pool;
11. @Override
12. public void run() {
13. pool = ConnectionPoolManager.getInstance().getPool("testPool");
14. }
15.
16. public Connection getConnection(){
17. Connection conn = null;
18. if(pool != null && pool.isActive()){
19. conn = pool.getConnection();
20. }
21. return conn;
22. }
23.
24. public Connection getCurrentConnection(){
25. Connection conn = null;
26. if(pool != null && pool.isActive()){
27. conn = pool.getCurrentConnecton();
28. }
29. return conn;
30. }
31. }
Java代码
1. package pool;
5. public class Client {
6. public static void main(String[] args) throws InterruptedException {
7. // 初始化连接池
8. Thread t = init();
9. t.start();
10. t.join();
11.
12. ThreadConnection a = new ThreadConnection();
13. ThreadConnection b = new ThreadConnection();
14. ThreadConnection c = new ThreadConnection();
15. Thread t1 = new Thread(a);
16. Thread t2 = new Thread(b);
17. Thread t3 = new Thread(c);
18.
19.
20. // 设置优先级,先让初始化执行,模拟 线程池 先启动
21. // 这里仅仅表面控制了,因为即使t 线程先启动,也不能保证pool 初始化完成,为了简单模拟,这里先这样写了
22. t1.setPriority(10);
23. t2.setPriority(10);
24. t3.setPriority(10);
25. t1.start();
26. t2.start();
27. t3.start();
28.
29. System.out.println("线程A-> "+a.getConnection());
30. System.out.println("线程B-> "+b.getConnection());
31. System.out.println("线程C-> "+c.getConnection());
32. }
33.
34. // 初始化
35. public static Thread init() {
36. Thread t = new Thread(new Runnable() {
37. @Override
38. public void run() {
39. IConnectionPool pool = initPool();
40. while(pool == null || !pool.isActive()){
41. pool = initPool();
42. }
43. }
44. });
45. return t;
46. }
47.
48. public static IConnectionPool initPool(){
49. return ConnectionPoolManager.getInstance().getPool("testPool");
50. }
51.
52. }
小结 :
1.连接池诞生原因是,如果每次都从数据库获得连接,时间比较长,因此我们提前做建立一些连接,放在连接池里面,每次都从里面取
2.上面仅仅写了连接池基本原理,关于多线程下连接池的管理没写,后面对多线程操作熟练了添加吧