2019独角兽企业重金招聘Python工程师标准>>>

connectionPool.DBConnectionManager

[java] view plain copy

  1. package connectionPool;
  2. import java.sql.Connection;
  3. import java.sql.Driver;
  4. import java.sql.DriverManager;
  5. import java.sql.SQLException;
  6. import java.util.ArrayList;
  7. import java.util.Enumeration;
  8. import java.util.HashSet;
  9. import java.util.Hashtable;
  10. import java.util.List;
  11. import java.util.Map;
  12. import java.util.Map.Entry;
  13. import java.util.Set;
  14. import connectionPool.util.Logger;
  15. import connectionPool.util.PropertiesMgr;
  16. /**
  17. * 连接池的设计思路
  18. * 1、
  19. * 初始化固定数目的连接(空闲连接与活跃连接在同一池中),建立连接的代理类,添加busy与startTime属性以便分发与回收连接
  20. * 另建立守护线程回收失效连接
  21. * 2、
  22. * 维护一空闲连接池,初始为空,需要连接时建立,用完的连接回收进入空闲连接池;
  23. * 后续所需连接从空闲连接池获取;activeNum记录活跃连接数目;
  24. * 当空闲连接池为空且活跃连接数达到上限时,请求等待,超时即获取连接失败,超时前有连接被释放方可获得连接
  25. * 第二个设计巧妙优势明显,采用第二种方式
  26. *
  27. * 数据库连接管理类,单例模式
  28. * 可以管理加载多个数据库驱动,维护多个数据库连接池
  29. * @author shijin
  30. *
  31. */
  32. public class DBConnectionManager {
  33. private static DBConnectionManager dbm = null;
  34. //单例模式里的成员变量都相当于是static了?
  35. /**
  36. * 客户数目
  37. */
  38. private static int clients = 0;
  39. /**
  40. * 加载的驱动器集合
  41. */
  42. private Set<Driver> drivers = new HashSet<Driver>();
  43. /**
  44. * 数据库连接池字典
  45. */
  46. private Hashtable<String,DBConnectionPool> pools = new Hashtable<String,DBConnectionPool>();
  47. private final Logger log = Logger.getInstance(DBConnectionPool.class);
  48. private DBConnectionManager() {
  49. loadDrivers();
  50. createPools();
  51. }
  52. /**
  53. * 装载和注册所有的JDBC驱动程序
  54. */
  55. private void loadDrivers() {
  56. String str_drivers = PropertiesMgr.getProperty("driver");
  57. for(String str_driver:str_drivers.split("\\s")) {
  58. Driver driver = null;
  59. try {
  60. driver = (Driver)Class.forName(str_driver).newInstance();
  61. DriverManager.registerDriver(driver);
  62. log.info("成功加载JDBC驱动:" + str_driver);
  63. } catch (InstantiationException e) {
  64. log.error("加载JDBC驱动" + str_driver + "时初始化异常,请检查配置文件");
  65. } catch (IllegalAccessException e) {
  66. log.info("加载JDBC驱动" + str_driver + "时非法访问,请检查配置文件");
  67. } catch (ClassNotFoundException e) {
  68. log.info("未找到JDBC驱动" + str_driver + "请引入相关包");
  69. } catch (SQLException e) {
  70. log.info("加载JDBC驱动" + str_driver + "失败,请检查引入包的正确性");
  71. }
  72. drivers.add(driver);
  73. }
  74. }
  75. /**
  76. * 根据配置文件创建数据库连接池
  77. */
  78. private void createPools() {
  79. Enumeration<?> elements = PropertiesMgr.propertiesNames();
  80. while(elements.hasMoreElements()) {
  81. String element = (String)elements.nextElement();
  82. if(element.endsWith(".url")) {
  83. String poolName = element.substring(0, element.lastIndexOf("."));
  84. String url = PropertiesMgr.getProperty(poolName + ".url");
  85. if(url == null) {
  86. log.error("无法连接到数据库" + poolName + "请检查配置文件连接字符串");
  87. continue;
  88. }
  89. String user = PropertiesMgr.getProperty(poolName + ".user");
  90. String pwd = PropertiesMgr.getProperty(poolName + ".password");
  91. String str_max = PropertiesMgr.getProperty(poolName + ".maxconn", "0");
  92. int maxConn = 0;
  93. try{
  94. maxConn = Integer.parseInt(str_max);
  95. }catch(NumberFormatException e) {
  96. log.error("数据库" + poolName + "最大连接数设置错误,默认设为20");
  97. maxConn = 20;
  98. }
  99. DBConnectionPool pool = new DBConnectionPool(maxConn,url,poolName,user,pwd);
  100. pools.put(poolName, pool);
  101. log.info("成功创建数据库连接池" + poolName);
  102. }
  103. }
  104. }
  105. /**
  106. * 获得单例
  107. * @return DBConnectionManager单例
  108. */
  109. public synchronized static DBConnectionManager getInstance() {
  110. if(dbm == null) {
  111. dbm = new DBConnectionManager();
  112. }
  113. clients++;
  114. return dbm;
  115. }
  116. /**
  117. * 从指定连接池中获取可用连接,无等待
  118. * @param poolName  要获取连接的连接池名称
  119. * @return  连接池中的一个可用连接或null
  120. */
  121. public Connection getConnection(String poolName) {
  122. DBConnectionPool pool = (DBConnectionPool)pools.get(poolName);
  123. return pool.getConnection();
  124. }
  125. /**
  126. * 从指定的连接池获取可用连接,有等待超时
  127. * @param poolName  要获取连接的连接池名称
  128. * @param timeout   获取可用连接的超时时间,单位为秒
  129. * @return          连接池中的一个可用连接或null
  130. */
  131. public Connection getConnection(String poolName,long timeout) {
  132. DBConnectionPool  pool = (DBConnectionPool)pools.get(poolName);
  133. return pool.getConnection(timeout);
  134. }
  135. /**
  136. * 回收指定连接池的连接
  137. * @param poolName  连接池名称
  138. * @param conn      要回收的连接
  139. */
  140. public void freeConnection(String poolName,Connection conn) {
  141. DBConnectionPool pool = (DBConnectionPool)pools.get(poolName);
  142. if(pool != null) {
  143. pool.freeConnection(conn);
  144. }
  145. log.error("找不到连接池,无法回收,请检查参数");
  146. }
  147. /**
  148. * 关闭所有连接,撤销驱动器的注册
  149. */
  150. public synchronized void release() {
  151. //所有客户连接都关闭时才真正关闭连接撤销注册
  152. if(clients-- != 0) {
  153. return;
  154. }
  155. for(Map.Entry<String,DBConnectionPool> poolEntry:pools.entrySet()) {
  156. DBConnectionPool pool = poolEntry.getValue();
  157. pool.releaseAll();
  158. }
  159. log.info("已经关闭所有连接");
  160. for(Driver driver:drivers) {
  161. try {
  162. DriverManager.deregisterDriver(driver);
  163. log.info("撤销JDBC驱动器" + driver.getClass().getName() + "的注册");
  164. } catch (SQLException e) {
  165. log.error("撤销JDBC驱动器" + driver.getClass().getName() + "的注册异常");
  166. }
  167. }
  168. log.info("驱动器撤销完成");
  169. }
  170. /**
  171. * 此内部类定义了一个连接池.
  172. * 它能够获取数据库连接,直到预定的最 大连接数为止
  173. * 在返回连接给客户程序之前,它能够验证连接的有效性
  174. * @author shijin
  175. */
  176. private class DBConnectionPool {
  177. private int activeNum = 0;
  178. private int maxConn = 0;
  179. private String url = null;
  180. private String poolName = null;
  181. private String user = null;
  182. private String pwd = null;
  183. private List<Connection> freeConnections = new ArrayList<Connection>();
  184. /**
  185. *
  186. * @param maxConn   设定的连接池允许的最大连接数
  187. * @param url       数据库连接url
  188. * @param poolName  连接池名称
  189. * @param user      数据库用户名,或null
  190. * @param pwd       数据库用户密码,或null
  191. */
  192. public DBConnectionPool(int maxConn, String url, String poolName,
  193. String user, String pwd) {
  194. super();
  195. this.maxConn = maxConn;
  196. this.url = url;
  197. this.poolName = poolName;
  198. this.user = user;
  199. this.pwd = pwd;
  200. }
  201. /**
  202. * 获得一个可用连接,不保证任何情况都能返回一个连接(比如超过最大连接数的时候返回null)
  203. * 1、若空闲连接池不为空,从空闲连接池取出一个连接后检查有效性,正常则返回,失效则重新获取连接
  204. * 2、若空闲连接池为空且未超过最大连接数限制,新建一个连接并返回
  205. * 3、空闲连接数为空且超过最大连接数限制,返回null
  206. * @return  获得的可用连接
  207. */
  208. public synchronized Connection getConnection() {
  209. Connection conn = null;
  210. //空闲连接池中有空闲连接,直接取
  211. if(freeConnections.size() > 0) {
  212. //从空闲连接池中取出一个连接
  213. conn = freeConnections.get(0);
  214. freeConnections.remove(0);
  215. //检测连接有效性
  216. try{
  217. if(conn.isClosed()) {
  218. //由于已经从空闲连接池取出,所以不使用无效连接其就无法重新进入
  219. //空闲连接池,意味着其已经被删除了,记入日志即可
  220. log.info("从连接池" + poolName + "中取出的连接已关闭,重新获取连接");
  221. //继续从连接池尝试获取连接
  222. conn = getConnection();
  223. }
  224. }catch(SQLException e) {
  225. log.info("从连接池" + poolName + "中取出的发生服务器访问错误,重新获取连接");
  226. conn = getConnection();
  227. }
  228. } else if(activeNum < maxConn) {
  229. conn = newConnection();
  230. } else {
  231. //未获得连接
  232. }
  233. if(conn != null) {
  234. activeNum++;
  235. }
  236. return conn;
  237. }
  238. /**
  239. * 当无空闲连接而又未达到最大连接数限制时创建新的连接
  240. * @return  新创建的连接
  241. */
  242. private Connection newConnection() {
  243. Connection conn = null;
  244. try{
  245. if(user == null) {
  246. conn = DriverManager.getConnection(url);
  247. } else {
  248. conn = DriverManager.getConnection(url, user, pwd);
  249. }
  250. log.info("与数据库" + poolName + "创建一个新连接");
  251. }catch(SQLException e) {
  252. log.error("无法根据\"" + url + "\"与数据库" + poolName + "建立新连接");
  253. }
  254. return conn;
  255. }
  256. /**
  257. * 获得一个可用连接,超过最大连接数时线程等待,直到有有连接释放时返回一个可用连接或者超时返回null
  258. * @param timeout 等待连接的超时时间,单位为秒
  259. * @return
  260. */
  261. public synchronized Connection getConnection(long timeout) {
  262. Connection conn = null;
  263. long startTime = System.currentTimeMillis();
  264. while((conn = getConnection()) == null) {
  265. try{
  266. //被notify(),notifyALL()唤醒或者超时自动苏醒
  267. wait(timeout);
  268. }catch(InterruptedException e) {
  269. log.error("等待连接的线程被意外打断");
  270. }
  271. //若线程在超时前被唤醒,则不会返回null,继续循环尝试获取连接
  272. if(System.currentTimeMillis() - startTime > timeout*1000000)
  273. return null;
  274. }
  275. return conn;
  276. }
  277. /**
  278. * 将释放的空闲连接加入空闲连接池,活跃连接数减一并激活等待连接的线程
  279. * @param conn  释放的连接
  280. */
  281. public synchronized void freeConnection(Connection conn) {
  282. freeConnections.add(conn);
  283. activeNum--;
  284. notifyAll();//通知正在由于达到最大连接数限制而wait的线程获取连接
  285. }
  286. /**
  287. * 关闭空闲连接池中的所有连接
  288. */
  289. public synchronized void releaseAll() {
  290. for(Connection conn:freeConnections) {
  291. try{
  292. conn.close();
  293. log.info("关闭空闲连接池" + poolName + "中的一个连接");
  294. }catch(SQLException e) {
  295. log.error("关闭空闲连接池" + poolName + "中的连接失败");
  296. }
  297. }
  298. freeConnections.clear();
  299. }
  300. }
  301. }

connectionpool.util.Logger

[java] view plain copy

  1. package connectionPool.util;
  2. import java.io.FileWriter;
  3. import java.io.IOException;
  4. import java.io.PrintWriter;
  5. import java.util.Date;
  6. /**
  7. * 日志文件创建维护类,单例模式
  8. * @author shijin
  9. *
  10. */
  11. public class Logger {
  12. private static Logger logger= null;
  13. private PrintWriter log = null;
  14. private static int level = 0;
  15. private Class<?> c = null;
  16. private static final int DEBUGLEVEL = 1;
  17. private static final int INFOLEVEL = 2;
  18. private static final int ERRORLEVEL = 3;
  19. private Logger(Class<?> c) {
  20. String logFileName = PropertiesMgr.getProperty("logfile","DBlog.txt");
  21. String str_level = PropertiesMgr.getProperty("loglevel", "3");
  22. this.c = c;
  23. level = Integer.parseInt(str_level);
  24. try {
  25. log = new PrintWriter(new FileWriter(logFileName),true);
  26. } catch (IOException e) {
  27. System.err.println("无法打开日志文件" + logFileName);
  28. log = new PrintWriter(System.err);
  29. }
  30. }
  31. public synchronized static Logger getInstance(Class<?> c) {
  32. if(logger == null) {
  33. logger = new Logger(c);
  34. }
  35. return logger;
  36. }
  37. public void debug(String msg) {
  38. if(level > DEBUGLEVEL) {
  39. msg = "DEBUG:" + new Date() + "-" + msg;
  40. System.out.println(msg);
  41. log.println(msg);
  42. }
  43. }
  44. public void info(String msg) {
  45. if(level > INFOLEVEL) {
  46. msg = "INFO:" + new Date() + "-" + msg;
  47. System.out.println(msg);
  48. log.println(msg);
  49. }
  50. }
  51. public void error(String msg) {
  52. if(level > ERRORLEVEL) {
  53. msg = "ERROR:" + new Date() + "-" + c + "-" + msg;
  54. System.out.println(msg);
  55. log.println(msg);
  56. }
  57. }
  58. }

connection.util.PropertiesMgr

[java] view plain copy

  1. package connectionPool.util;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.util.Enumeration;
  5. import java.util.Properties;
  6. /**
  7. * 属性文件加载管理类,单例模式
  8. * @author shijin
  9. *
  10. */
  11. public class PropertiesMgr {
  12. private static Properties pro = new Properties();
  13. private PropertiesMgr(){}
  14. static {
  15. try {
  16. pro.load(PropertiesMgr.class.getClassLoader().getResourceAsStream("config" + File.separator + "DB.properties"));
  17. } catch (IOException e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. public static String getProperty(String key) {
  22. return pro.getProperty(key);
  23. }
  24. public static String getProperty(String key,String defaultValue) {
  25. //找不到key用defaultValue,而不是说后面为空字符串采用defaultValue
  26. return pro.getProperty(key, defaultValue);
  27. }
  28. public static Enumeration<?> propertiesNames() {
  29. return pro.propertyNames();
  30. }
  31. }

DB.properties

[plain] view plain copy

  1. driver=com.mysql.jdbc.Driver
  2. mysql.url=jdbc:mysql://127.0.0.1/caiwu?useUnicode=true&characterEncoding=gb2312
  3. mysql.user=root
  4. mysql.password=123
  5. mysql.maxconn=1000
  6. #\u65E5\u5FD7\u6587\u4EF6\u7684\u540D\u79F0
  7. logfile=
  8. #\u65E5\u5FD7\u7EA7\u522B
  9. loglevel=

转载于:https://my.oschina.net/newchaos/blog/1555846

数据库连接池的设计思路及java实现相关推荐

  1. sqlrelay mysql_数据库连接池SQL Relay安装使用-Java架构师必看

    SQLRelay按照其官网http://sqlrelay.sourceforge.net/indePHP SQL Relay按照其官网http://sqlrelay.sourceforge.net/i ...

  2. Go协程池设计思路(Task-Job-Worker)

    1. 铺垫:Go 的接收器Receiver 在go语言中,没有类的概念,但是可以给类型(结构体,自定义类型)定义方法.所谓方法就是定义了接受者的函数.接受者定义在func关键字和函数名之间.可以理解成 ...

  3. 01_数据库连接池,数据源,ResultSetMetaData,jdbc优化

     一.数据库连接池 1. 什么是连接池 传统的开发模式下,Servlet处理用户的请求,找Dao查询数据,dao会创建与数据库之间的连接,完成数据查询后会关闭数据库的链接. 这样的方式会导致用户每 ...

  4. 数据库连接池 DBCP和c3p0数据库连接池

    一.数据库连接池 1. 什么是连接池 传统的开发模式下,Servlet处理用户的请求,找Dao查询数据,dao会创建与数据库之间的连接,完成数据查询后会关闭数据库的链接. 这样的方式会导致用户每次请求 ...

  5. 池化技术-数据库连接池

    池化技术-数据库连接池 简介 数据库连接池 什么是数据库连接池 长连接和连接池的区别 数据库连接池运行机制 连接池和线程池的关系 连接池的连接数量 数据库连接池的设计 设计思路 设计逻辑 构造函数 初 ...

  6. 数据库连接池连接数量配置多大合理

    前段时间在一个老项目中经历过一个问题:一个 Dubbo 服务,启动的时候慢的要死,后来看日志查原因整个过程一直在初始化数据库连接.一看数据库连接参数,连接池大小:1024. 很多入行晚的同学没有经历过 ...

  7. 数据库连接池,实现及分析

    在我们日常对数据库操作时存在一个问题,要为每次数据操作请求建立一个数据库连接.而每次建立连接都需要花费很多开销,如加载驱动类.注册驱动.获取连接,这样如果在短时间内连接多次,就 会耗费多余的时间(加载 ...

  8. JavaWeb:JDBC之数据库连接池

    JDBC系列阅读 JavaWeb:用JDBC操作数据库 JavaWeb:JDBC之事务 JavaWeb:JDBC之数据库连接池 使用JDBC实现水果超市管理系统 1. 池参数(所有池参数都有默认值) ...

  9. Golang 侧数据库连接池原理和参数调优

    Golang 侧数据库连接池原理和参数调优 文章目录 Golang 侧数据库连接池原理和参数调优 数据库连接池 数据库连接池的设计 Go 的数据库连接池 Go 数据库连接池的设计 建立连接 释放连接 ...

最新文章

  1. 独家 | 带你认识HDFS和如何创建3个节点HDFS集群(附代码案例)
  2. JavaScript实现放大镜功能
  3. Google面试题及答案
  4. DOM Xerces类库使用方法
  5. vba 循环读取单元格_利用VBA打开顺序文件,并读取
  6. 关天asp.net ajax beta中在updatepnael中注册脚本的解决方案
  7. golang map转json的顺序问题
  8. nod32 lic 99用户授权文件可以用到2015年4月的许可证下载
  9. 示波器探头各种作用及工作原理,你都理解清楚了吗?
  10. 【刷题】洛谷 P4142 洞穴遇险
  11. mysql中的round函数
  12. 软件测试发展前景进阶路线(最全面)
  13. 独热码状态机、SR锁存器延迟模型、移位除法器模型
  14. 万能DOS启动盘制作全攻略!(软盘+光盘+U盘+硬盘+NTFS+……)
  15. KYC功能介绍:为客户提供新的机会
  16. 八一电大c语言程序设计,2019年中央电大本科《生产与运作管理》期末考试资料...
  17. 【无标题】Java实现进度条代码
  18. 最新勒索病毒扩展名.actin,.2k19sys,.help,.lanset的特征分析,常见处理方式
  19. 磁学基础 永久磁铁的磁力线分布
  20. 单机100万连接,每秒10万次请求服务端的设计与实现(一) - 前传

热门文章

  1. java如何实现信号量_使用二进制信号量实现通用信号量
  2. php stream encoding,PHP之mb_check_encoding使用方法分享
  3. php改变iframe的src,js动态改变iframe的src属性
  4. 如何备份数据_如何通过归档、备份和灾难恢复实现多云数据保护
  5. linux启动tongweb命令,linux7开机自启动东方通tongweb
  6. 为什么苹果内购总是失败_IOS用户支付失败 购买无法完成解决教程
  7. C++语言程序设计上机指导(二级),C++语言程序设计上机指导(二级)
  8. 中计算散度的函数_梯度、散度、旋度
  9. 跨域会报40几_总结一下跨域的几种情况
  10. java 日期操作工具类_java8操作日期的工具类