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. private int initConnections = 5;// 初始化连接数
  19. private long connTimeOut = 1000;// 重复获得连接的频率
  20. private int maxActiveConnections = 100;// 最大允许的连接数,和数据库对应
  21. private long connectionTimeOut = 1000*60*20;// 连接超时时间,默认20分钟
  22. private boolean isCurrentConnection = true; // 是否获得当前连接,默认true
  23. private boolean isCheakPool = true; // 是否定时检查连接池
  24. private long lazyCheck = 1000*60*60;// 延迟多少时间后开始 检查
  25. private long periodCheck = 1000*60*60;// 检查频率
  26. public DBbean(String driverName, String url, String userName,
  27. String password, String poolName) {
  28. super();
  29. this.driverName = driverName;
  30. this.url = url;
  31. this.userName = userName;
  32. this.password = password;
  33. this.poolName = poolName;
  34. }
  35. public DBbean() {
  36. }
  37. public String getDriverName() {
  38. if(driverName == null){
  39. driverName = this.getDriverName()+"_"+this.getUrl();
  40. }
  41. return driverName;
  42. }
  43. public void setDriverName(String driverName) {
  44. this.driverName = driverName;
  45. }
  46. public String getUrl() {
  47. return url;
  48. }
  49. public void setUrl(String url) {
  50. this.url = url;
  51. }
  52. public String getUserName() {
  53. return userName;
  54. }
  55. public void setUserName(String userName) {
  56. this.userName = userName;
  57. }
  58. public String getPassword() {
  59. return password;
  60. }
  61. public void setPassword(String password) {
  62. this.password = password;
  63. }
  64. public String getPoolName() {
  65. return poolName;
  66. }
  67. public void setPoolName(String poolName) {
  68. this.poolName = poolName;
  69. }
  70. public int getMinConnections() {
  71. return minConnections;
  72. }
  73. public void setMinConnections(int minConnections) {
  74. this.minConnections = minConnections;
  75. }
  76. public int getMaxConnections() {
  77. return maxConnections;
  78. }
  79. public void setMaxConnections(int maxConnections) {
  80. this.maxConnections = maxConnections;
  81. }
  82. public int getInitConnections() {
  83. return initConnections;
  84. }
  85. public void setInitConnections(int initConnections) {
  86. this.initConnections = initConnections;
  87. }
  88. public int getMaxActiveConnections() {
  89. return maxActiveConnections;
  90. }
  91. public void setMaxActiveConnections(int maxActiveConnections) {
  92. this.maxActiveConnections = maxActiveConnections;
  93. }
  94. public long getConnTimeOut() {
  95. return connTimeOut;
  96. }
  97. public void setConnTimeOut(long connTimeOut) {
  98. this.connTimeOut = connTimeOut;
  99. }
  100. public long getConnectionTimeOut() {
  101. return connectionTimeOut;
  102. }
  103. public void setConnectionTimeOut(long connectionTimeOut) {
  104. this.connectionTimeOut = connectionTimeOut;
  105. }
  106. public boolean isCurrentConnection() {
  107. return isCurrentConnection;
  108. }
  109. public void setCurrentConnection(boolean isCurrentConnection) {
  110. this.isCurrentConnection = isCurrentConnection;
  111. }
  112. public long getLazyCheck() {
  113. return lazyCheck;
  114. }
  115. public void setLazyCheck(long lazyCheck) {
  116. this.lazyCheck = lazyCheck;
  117. }
  118. public long getPeriodCheck() {
  119. return periodCheck;
  120. }
  121. public void setPeriodCheck(long periodCheck) {
  122. this.periodCheck = periodCheck;
  123. }
  124. public boolean isCheakPool() {
  125. return isCheakPool;
  126. }
  127. public void setCheakPool(boolean isCheakPool) {
  128. this.isCheakPool = isCheakPool;
  129. }
  130. }

Java代码  

  1. package pool;
  2. import java.sql.Connection;
  3. import java.sql.SQLException;
  4. public interface IConnectionPool {
  5. // 获得连接
  6. public Connection  getConnection();
  7. // 获得当前连接
  8. public Connection getCurrentConnecton();
  9. // 回收连接
  10. public void releaseConn(Connection conn) throws SQLException;
  11. // 销毁清空
  12. public void destroy();
  13. // 连接池是活动状态
  14. public boolean isActive();
  15. // 定时器,检查连接池
  16. public void cheackPool();
  17. }

Java代码  

  1. package pool;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.SQLException;
  5. import java.util.List;
  6. import java.util.Timer;
  7. import java.util.TimerTask;
  8. import java.util.Vector;
  9. public class ConnectionPool implements IConnectionPool {
  10. // 连接池配置属性
  11. private DBbean dbBean;
  12. private boolean isActive = false; // 连接池活动状态
  13. private int contActive = 0;// 记录创建的总的连接数
  14. // 空闲连接
  15. private List<Connection> freeConnection = new Vector<Connection>();
  16. // 活动连接
  17. private List<Connection> activeConnection = new Vector<Connection>();
  18. // 将线程和连接绑定,保证事务能统一执行
  19. private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
  20. public ConnectionPool(DBbean dbBean) {
  21. super();
  22. this.dbBean = dbBean;
  23. init();
  24. cheackPool();
  25. }
  26. // 初始化
  27. public void init() {
  28. try {
  29. Class.forName(dbBean.getDriverName());
  30. for (int i = 0; i < dbBean.getInitConnections(); i++) {
  31. Connection conn;
  32. conn = newConnection();
  33. // 初始化最小连接数
  34. if (conn != null) {
  35. freeConnection.add(conn);
  36. contActive++;
  37. }
  38. }
  39. isActive = true;
  40. } catch (ClassNotFoundException e) {
  41. e.printStackTrace();
  42. } catch (SQLException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. // 获得当前连接
  47. public Connection getCurrentConnecton(){
  48. // 默认线程里面取
  49. Connection conn = threadLocal.get();
  50. if(!isValid(conn)){
  51. conn = getConnection();
  52. }
  53. return conn;
  54. }
  55. // 获得连接
  56. public synchronized Connection getConnection() {
  57. Connection conn = null;
  58. try {
  59. // 判断是否超过最大连接数限制
  60. if(contActive < this.dbBean.getMaxActiveConnections()){
  61. if (freeConnection.size() > 0) {
  62. conn = freeConnection.get(0);
  63. if (conn != null) {
  64. threadLocal.set(conn);
  65. }
  66. freeConnection.remove(0);
  67. } else {
  68. conn = newConnection();
  69. }
  70. }else{
  71. // 继续获得连接,直到从新获得连接
  72. wait(this.dbBean.getConnTimeOut());
  73. conn = getConnection();
  74. }
  75. if (isValid(conn)) {
  76. activeConnection.add(conn);
  77. contActive ++;
  78. }
  79. } catch (SQLException e) {
  80. e.printStackTrace();
  81. } catch (ClassNotFoundException e) {
  82. e.printStackTrace();
  83. } catch (InterruptedException e) {
  84. e.printStackTrace();
  85. }
  86. return conn;
  87. }
  88. // 获得新连接
  89. private synchronized Connection newConnection()
  90. throws ClassNotFoundException, SQLException {
  91. Connection conn = null;
  92. if (dbBean != null) {
  93. Class.forName(dbBean.getDriverName());
  94. conn = DriverManager.getConnection(dbBean.getUrl(),
  95. dbBean.getUserName(), dbBean.getPassword());
  96. }
  97. return conn;
  98. }
  99. // 释放连接
  100. public synchronized void releaseConn(Connection conn) throws SQLException {
  101. if (isValid(conn)&& !(freeConnection.size() > dbBean.getMaxConnections())) {
  102. freeConnection.add(conn);
  103. activeConnection.remove(conn);
  104. contActive --;
  105. threadLocal.remove();
  106. // 唤醒所有正待等待的线程,去抢连接
  107. notifyAll();
  108. }
  109. }
  110. // 判断连接是否可用
  111. private boolean isValid(Connection conn) {
  112. try {
  113. if (conn == null || conn.isClosed()) {
  114. return false;
  115. }
  116. } catch (SQLException e) {
  117. e.printStackTrace();
  118. }
  119. return true;
  120. }
  121. // 销毁连接池
  122. public synchronized void destroy() {
  123. for (Connection conn : freeConnection) {
  124. try {
  125. if (isValid(conn)) {
  126. conn.close();
  127. }
  128. } catch (SQLException e) {
  129. e.printStackTrace();
  130. }
  131. }
  132. for (Connection conn : activeConnection) {
  133. try {
  134. if (isValid(conn)) {
  135. conn.close();
  136. }
  137. } catch (SQLException e) {
  138. e.printStackTrace();
  139. }
  140. }
  141. isActive = false;
  142. contActive = 0;
  143. }
  144. // 连接池状态
  145. @Override
  146. public boolean isActive() {
  147. return isActive;
  148. }
  149. // 定时检查连接池情况
  150. @Override
  151. public void cheackPool() {
  152. if(dbBean.isCheakPool()){
  153. new Timer().schedule(new TimerTask() {
  154. @Override
  155. public void run() {
  156. // 1.对线程里面的连接状态
  157. // 2.连接池最小 最大连接数
  158. // 3.其他状态进行检查,因为这里还需要写几个线程管理的类,暂时就不添加了
  159. System.out.println("空线池连接数:"+freeConnection.size());
  160. System.out.println("活动连接数::"+activeConnection.size());
  161. System.out.println("总的连接数:"+contActive);
  162. }
  163. },dbBean.getLazyCheck(),dbBean.getPeriodCheck());
  164. }
  165. }
  166. }

Java代码  

  1. package pool;
  2. import java.sql.Connection;
  3. import java.sql.SQLException;
  4. import java.util.Hashtable;
  5. /**
  6. * 连接管理类
  7. * @author Ran
  8. *
  9. */
  10. public class ConnectionPoolManager {
  11. // 连接池存放
  12. public Hashtable<String,IConnectionPool> pools = new Hashtable<String, IConnectionPool>();
  13. // 初始化
  14. private ConnectionPoolManager(){
  15. init();
  16. }
  17. // 单例实现
  18. public static ConnectionPoolManager getInstance(){
  19. return Singtonle.instance;
  20. }
  21. private static class Singtonle {
  22. private static ConnectionPoolManager instance =  new ConnectionPoolManager();
  23. }
  24. // 初始化所有的连接池
  25. public void init(){
  26. for(int i =0;i<DBInitInfo.beans.size();i++){
  27. DBbean bean = DBInitInfo.beans.get(i);
  28. ConnectionPool pool = new ConnectionPool(bean);
  29. if(pool != null){
  30. pools.put(bean.getPoolName(), pool);
  31. System.out.println("Info:Init connection successed ->" +bean.getPoolName());
  32. }
  33. }
  34. }
  35. // 获得连接,根据连接池名字 获得连接
  36. public Connection  getConnection(String poolName){
  37. Connection conn = null;
  38. if(pools.size()>0 && pools.containsKey(poolName)){
  39. conn = getPool(poolName).getConnection();
  40. }else{
  41. System.out.println("Error:Can‘t find this connecion pool ->"+poolName);
  42. }
  43. return conn;
  44. }
  45. // 关闭,回收连接
  46. public void close(String poolName,Connection conn){
  47. IConnectionPool pool = getPool(poolName);
  48. try {
  49. if(pool != null){
  50. pool.releaseConn(conn);
  51. }
  52. } catch (SQLException e) {
  53. System.out.println("连接池已经销毁");
  54. e.printStackTrace();
  55. }
  56. }
  57. // 清空连接池
  58. public void destroy(String poolName){
  59. IConnectionPool pool = getPool(poolName);
  60. if(pool != null){
  61. pool.destroy();
  62. }
  63. }
  64. // 获得连接池
  65. public IConnectionPool getPool(String poolName){
  66. IConnectionPool pool = null;
  67. if(pools.size() > 0){
  68. pool = pools.get(poolName);
  69. }
  70. return pool;
  71. }
  72. }

Java代码  

  1. package pool;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. /**
  5. * 初始化,模拟加载所有的配置文件
  6. * @author Ran
  7. *
  8. */
  9. public class DBInitInfo {
  10. public  static List<DBbean>  beans = null;
  11. static{
  12. beans = new ArrayList<DBbean>();
  13. // 这里数据 可以从xml 等配置文件进行获取
  14. // 为了测试,这里我直接写死
  15. DBbean beanOracle = new DBbean();
  16. beanOracle.setDriverName("oracle.jdbc.driver.OracleDriver");
  17. beanOracle.setUrl("jdbc:oracle:thin:@7MEXGLUY95W1Y56:1521:orcl");
  18. beanOracle.setUserName("mmsoa");
  19. beanOracle.setPassword("password1234");
  20. beanOracle.setMinConnections(5);
  21. beanOracle.setMaxConnections(100);
  22. beanOracle.setPoolName("testPool");
  23. beans.add(beanOracle);
  24. }
  25. }

测试:

Java代码  

  1. package pool;
  2. import java.sql.Connection;
  3. /**
  4. * 模拟线程启动,去获得连接
  5. * @author Ran
  6. *
  7. */
  8. public class ThreadConnection implements Runnable{
  9. private IConnectionPool pool;
  10. @Override
  11. public void run() {
  12. pool = ConnectionPoolManager.getInstance().getPool("testPool");
  13. }
  14. public Connection getConnection(){
  15. Connection conn = null;
  16. if(pool != null && pool.isActive()){
  17. conn = pool.getConnection();
  18. }
  19. return conn;
  20. }
  21. public Connection getCurrentConnection(){
  22. Connection conn = null;
  23. if(pool != null && pool.isActive()){
  24. conn = pool.getCurrentConnecton();
  25. }
  26. return conn;
  27. }
  28. }

Java代码  

  1. package pool;
  2. public class Client {
  3. public static void main(String[] args) throws InterruptedException {
  4. // 初始化连接池
  5. Thread t = init();
  6. t.start();
  7. t.join();
  8. ThreadConnection a = new ThreadConnection();
  9. ThreadConnection b = new ThreadConnection();
  10. ThreadConnection c = new ThreadConnection();
  11. Thread t1 = new Thread(a);
  12. Thread t2 = new Thread(b);
  13. Thread t3 = new Thread(c);
  14. // 设置优先级,先让初始化执行,模拟 线程池 先启动
  15. // 这里仅仅表面控制了,因为即使t 线程先启动,也不能保证pool 初始化完成,为了简单模拟,这里先这样写了
  16. t1.setPriority(10);
  17. t2.setPriority(10);
  18. t3.setPriority(10);
  19. t1.start();
  20. t2.start();
  21. t3.start();
  22. System.out.println("线程A-> "+a.getConnection());
  23. System.out.println("线程B-> "+b.getConnection());
  24. System.out.println("线程C-> "+c.getConnection());
  25. }
  26. // 初始化
  27. public static Thread init() {
  28. Thread t = new Thread(new Runnable() {
  29. @Override
  30. public void run() {
  31. IConnectionPool  pool = initPool();
  32. while(pool == null || !pool.isActive()){
  33. pool = initPool();
  34. }
  35. }
  36. });
  37. return t;
  38. }
  39. public static IConnectionPool initPool(){
  40. return ConnectionPoolManager.getInstance().getPool("testPool");
  41. }
  42. }

小结 :

1.连接池诞生原因是,如果每次都从数据库获得连接,时间比较长,因此我们提前做建立一些连接,放在连接池里面,每次都从里面取

2.上面仅仅写了连接池基本原理,关于多线程下连接池的管理没写,后面对多线程操作熟练了添加吧

本文转自http://greemranqq.iteye.com/blog/1969273 感谢作者

时间: 2024-08-11 07:47:21

JAVA数据库连接池实现(转)的相关文章

Java数据库连接池

写了个 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 protec

java数据库连接池dbcp的使用

近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机 应用程序已从传统的桌面应用转到Web应用.基于B/S(Browser/Server)架构的3层开发模式逐渐取代C/S(Client/Server)架构的开发模式,成为开发企业级应用和电子商务普遍采用的技术. 在Java语言中,JDBC(Java DataBase Connection)是应用程序与数据库沟通的桥梁, 即Java语言通过JDBC技术访问数据库.JDBC是一种"开放"的方案,它

java 数据库连接池 Oracle版

首先应加入连接池和数据库连接的配置文件:数据库连接包:ojdbc6.jar数据库连接池包:commons-pool2-2.2.jar                       commons-dbcp2-2.0.jar数据库连接配置文件:config.properties使用连接池连接一定不要忘记关闭否则会很倒霉DBHelper 的写法 import java.io.IOException;import java.io.InputStream;import java.sql.Connectio

java数据库连接池实现原理

一.为什么在连接数据库时要使用连接池 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.  一个数据库连接对象均对应一个物理数据库连接,每次操作都打开一个物理连接,使用完都关闭连接,这样造成系统的 性能低下. 数据库连接池的解决方案是在应用程序启动时建立足够的数据库连接,并讲这些连接组成一个连接池(简单说:在一个"池"里放了好多半成品的数据库联接对象),由应用程序动态地对池中的连接进行申请.使用和释放.对于多于连接池中连接数的并发请求,应该在请求队列

java数据库连接池性能对比

这个测试的目的是验证当前常用数据库连接池的性能. testcase Connection conn = dataSource.getConnection(); PreparedStatement stmt = conn.preparedStatement("select 1"); ResultSet rs = stmt.executeQuery(); while (rs.next()) { } rs.close(); stmt.close(); conn.close(); test c

一个效果非常不错的JAVA数据库连接池

package studytest; ////    一个效果非常不错的JAVA数据库连接池.//    from:http://www.jxer.com/home/?uid-195-action-viewspace-itemid-332//    虽然现在用APACHE COMMONS DBCP可以非常方便的建立数据库连接池,//    但是像这篇文章把数据库连接池的内部原理写的这么透彻,注视这么完整,//    真是非常难得,让开发人员可以更深层次的理解数据库连接池,真是非常感//    谢

Java数据库连接池详解

http://www.javaweb1024.com/java/JavaWebzhongji/2015/06/01/736.html 对于共享资源,有一个很著名的设计模式:资源池(Resource Pool).该模式正是为了解决资源的频繁分配﹑释放所造成的问题.为解决我们的问题,可以采用数据库连接池技术.数据库连接池的基本思想就是为数据库连接建立一个"缓冲池".预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从"缓冲池"中取出一个,使用完毕之后再放回去

[转帖]为什么HikariCP被号称为性能最好的Java数据库连接池,如何配置使用

为什么HikariCP被号称为性能最好的Java数据库连接池,如何配置使用 原创Clement-Xu 发布于2015-07-17 15:53:14 阅读数 57066  收藏 展开 HiKariCP是数据库连接池的一个后起之秀,号称性能最好,可以完美地PK掉其他连接池. 原文地址:http://blog.csdn.net/clementad/article/details/46928621 官网:https://github.com/brettwooldridge/HikariCP 为何要使用H

[数据库连接池] Java数据库连接池--DBCP浅析.

前言对于数据库连接池, 想必大家都已经不再陌生, 这里仅仅设计Java中的两个常用数据库连接池: DBCP和C3P0(后续会更新). 一. 为何要使用数据库连接池假设网站一天有很大的访问量,数据库服务器就需要为每次连接创建一次数据库连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出.拓机.数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正式针对这个问题提

java数据库连接池技术简单使用

JDBCDemo.java: package com.itheima.jdbc; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import com.itheima.pool.MyPool; public class JDBCDemo { public static void main(String[]