[关闭]
@yulongsun 2017-03-25T07:27:20.000000Z 字数 9335 阅读 1044

数据库连接池实现原理

java


1. 目的

为了实现对`对象Connection`的重用。

2. 实现

2.1 创建自定义的连接池

  1. //创建自定义的连接池
  2. 1、以下是类的源代码,使用的是MySql数据库,代码较多,请注意阅读。
  3. package cn.itcast.connectionpool;
  4. import java.sql.Array;
  5. import java.sql.Blob;
  6. import java.sql.CallableStatement;
  7. import java.sql.Clob;
  8. import java.sql.Connection;
  9. import java.sql.DatabaseMetaData;
  10. import java.sql.DriverManager;
  11. import java.sql.NClob;
  12. import java.sql.PreparedStatement;
  13. import java.sql.SQLClientInfoException;
  14. import java.sql.SQLException;
  15. import java.sql.SQLWarning;
  16. import java.sql.SQLXML;
  17. import java.sql.Savepoint;
  18. import java.sql.Statement;
  19. import java.sql.Struct;
  20. import java.util.LinkedList;
  21. import java.util.Map;
  22. import java.util.Properties;
  23. /**
  24. * 我的连接池
  25. * 通过此连接池的实现,用户只能通过 - 包装代理。
  26. * MyConnectionPool.getConnection()来获取连接
  27. * 且当用户关闭连接时并没有真的关闭,而是将此对连接又放回到LinkedList中。
  28. * @author <a href="wangjian_me@126.com">王健</a>
  29. */
  30. public class MyConnectionPool {
  31. private MyConnectionPool(){}//声明一个私有的构造不允许别人创建
  32. //声明连接的字符串,可以使用动态加载,即从资源文件加载
  33. private static String url="jdbc:mysql://127.0.0.1:3306/itcast";
  34. //声明用户存放连接类
  35. private static LinkedList<Connection> connections = new LinkedList<Connection>();
  36. //仍然是在static中初始化
  37. static{
  38. try{
  39. Class.forName("com.mysql.jdbc.Driver");
  40. for(int i=0;i<5;i++){//声明初始化有5个连接
  41. Connection con = DriverManager.getConnection(url,"root","root");
  42. connections.addLast(new ItcastConnection(con));//退加到最后
  43. }
  44. System.err.println("共有几个连接:"+connections.size());
  45. }catch(Exception e){
  46. e.printStackTrace();
  47. }
  48. }
  49. /**
  50. * 获取一个连接
  51. */
  52. public static Connection getConnection(){
  53. if(connections.size()<=0){
  54. throw new RuntimeException("已经没有可用的连接,或用户使用了连接后没有关闭。");
  55. }
  56. return connections.removeFirst();//返回第一个
  57. }
  58. /**
  59. * 声明成内部私有类,外部的任何人不可以访问
  60. * 以下使用了个"假"代理来完成Connection的功能
  61. * 请注意实现的close方法,并没有关闭连接。
  62. * @author <a href="wangjian_me@126.com">王健</a>
  63. */
  64. static private class ItcastConnection implements Connection {
  65. private Connection realConnection; // 直接的连接
  66. /**
  67. * 私有的方法
  68. */
  69. private ItcastConnection(Connection con){
  70. this.realConnection = con;
  71. }
  72. //下面的方法只是简单的调用realConnection的实现而已
  73. public void clearWarnings() throws SQLException {
  74. realConnection.clearWarnings();
  75. }
  76. @Override
  77. public void close() throws SQLException {
  78. System.err.println("连接关闭了......");
  79. connections.addLast(this); //再次自己加回去
  80. //realConnection.close();
  81. //为了不影响以用户习惯的代码编写所以一个简单的类包裹实现代理,当用户关闭连接时,其实是将此连接更追加到链表的尾部。
  82. //此功能可以一步步的引导学生完成,从最基本的强制用户调用一个方法将连接追加到尾部到实现自动的追加到尾部。
  83. }
  84. @Override
  85. public void commit() throws SQLException {
  86. realConnection.commit();
  87. }
  88. @Override
  89. public Array createArrayOf(String typeName, Object[] elements)
  90. throws SQLException {
  91. return realConnection.createArrayOf(typeName, elements);
  92. }
  93. @Override
  94. public Blob createBlob() throws SQLException {
  95. return realConnection.createBlob();
  96. }
  97. @Override
  98. public Clob createClob() throws SQLException {
  99. return realConnection.createClob();
  100. }
  101. @Override
  102. public NClob createNClob() throws SQLException {
  103. return realConnection.createNClob();
  104. }
  105. @Override
  106. public SQLXML createSQLXML() throws SQLException {
  107. return realConnection.createSQLXML();
  108. }
  109. public Statement createStatement() throws SQLException {
  110. return realConnection.createStatement();
  111. }
  112. @Override
  113. public Statement createStatement(int resultSetType, int resultSetConcurrency)
  114. throws SQLException {
  115. return realConnection.createStatement(resultSetType, resultSetConcurrency);
  116. }
  117. @Override
  118. public Statement createStatement(int resultSetType,
  119. int resultSetConcurrency, int resultSetHoldability)
  120. throws SQLException {
  121. return realConnection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
  122. }
  123. public Struct createStruct(String typeName, Object[] attributes)
  124. throws SQLException {
  125. return realConnection.createStruct(typeName, attributes);
  126. }
  127. @Override
  128. public boolean getAutoCommit() throws SQLException {
  129. return realConnection.getAutoCommit();
  130. }
  131. @Override
  132. public String getCatalog() throws SQLException {
  133. return realConnection.getCatalog();
  134. }
  135. @Override
  136. public Properties getClientInfo() throws SQLException {
  137. return realConnection.getClientInfo();
  138. }
  139. @Override
  140. public String getClientInfo(String name) throws SQLException {
  141. return realConnection.getClientInfo(name);
  142. }
  143. public int getHoldability() throws SQLException {
  144. return realConnection.getHoldability();
  145. }
  146. @Override
  147. public DatabaseMetaData getMetaData() throws SQLException {
  148. return realConnection.getMetaData();
  149. }
  150. @Override
  151. public int getTransactionIsolation() throws SQLException {
  152. return realConnection.getTransactionIsolation();
  153. }
  154. @Override
  155. public Map<String, Class<?>> getTypeMap() throws SQLException {
  156. return realConnection.getTypeMap();
  157. }
  158. @Override
  159. public SQLWarning getWarnings() throws SQLException {
  160. return realConnection.getWarnings();
  161. }
  162. @Override
  163. public boolean isClosed() throws SQLException {
  164. return realConnection.isClosed();
  165. }
  166. @Override
  167. public boolean isReadOnly() throws SQLException {
  168. return realConnection.isReadOnly();
  169. }
  170. @Override
  171. public boolean isValid(int timeout) throws SQLException {
  172. return realConnection.isValid(timeout);
  173. }
  174. @Override
  175. public String nativeSQL(String sql) throws SQLException {
  176. return realConnection.nativeSQL(sql);
  177. }
  178. @Override
  179. public CallableStatement prepareCall(String sql) throws SQLException {
  180. return realConnection.prepareCall(sql);
  181. }
  182. @Override
  183. public CallableStatement prepareCall(String sql, int resultSetType,
  184. int resultSetConcurrency) throws SQLException {
  185. return realConnection.prepareCall(sql);
  186. }
  187. @Override
  188. public CallableStatement prepareCall(String sql, int resultSetType,
  189. int resultSetConcurrency, int resultSetHoldability)
  190. throws SQLException {
  191. return realConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  192. }
  193. @Override
  194. public PreparedStatement prepareStatement(String sql) throws SQLException {
  195. return realConnection.prepareStatement(sql);
  196. }
  197. @Override
  198. public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
  199. throws SQLException {
  200. return realConnection.prepareStatement(sql, autoGeneratedKeys);
  201. }
  202. @Override
  203. public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
  204. throws SQLException {
  205. return realConnection.prepareStatement(sql, columnIndexes);
  206. }
  207. @Override
  208. public PreparedStatement prepareStatement(String sql, String[] columnNames)
  209. throws SQLException {
  210. return realConnection.prepareStatement(sql, columnNames);
  211. }
  212. @Override
  213. public PreparedStatement prepareStatement(String sql, int resultSetType,
  214. int resultSetConcurrency) throws SQLException {
  215. return realConnection.prepareStatement(sql, resultSetType, resultSetConcurrency);
  216. }
  217. @Override
  218. public PreparedStatement prepareStatement(String sql, int resultSetType,
  219. int resultSetConcurrency, int resultSetHoldability)
  220. throws SQLException {
  221. return realConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  222. }
  223. @Override
  224. public void releaseSavepoint(Savepoint savepoint) throws SQLException {
  225. realConnection.releaseSavepoint(savepoint);
  226. }
  227. @Override
  228. public void rollback() throws SQLException {
  229. realConnection.rollback();
  230. }
  231. @Override
  232. public void rollback(Savepoint savepoint) throws SQLException {
  233. realConnection.rollback(savepoint);
  234. }
  235. @Override
  236. public void setAutoCommit(boolean autoCommit) throws SQLException {
  237. realConnection.setAutoCommit(autoCommit);
  238. }
  239. @Override
  240. public void setCatalog(String catalog) throws SQLException {
  241. realConnection.setCatalog(catalog);
  242. }
  243. @Override
  244. public void setClientInfo(Properties properties)
  245. throws SQLClientInfoException {
  246. realConnection.setClientInfo(properties);
  247. }
  248. @Override
  249. public void setClientInfo(String name, String value)
  250. throws SQLClientInfoException {
  251. realConnection.setClientInfo(name, value);
  252. }
  253. @Override
  254. public void setHoldability(int holdability) throws SQLException {
  255. realConnection.setHoldability(holdability);
  256. }
  257. @Override
  258. public void setReadOnly(boolean readOnly) throws SQLException {
  259. realConnection.setReadOnly(readOnly);
  260. }
  261. @Override
  262. public Savepoint setSavepoint() throws SQLException {
  263. return realConnection.setSavepoint();
  264. }
  265. @Override
  266. public Savepoint setSavepoint(String name) throws SQLException {
  267. return realConnection.setSavepoint(name);
  268. }
  269. @Override
  270. public void setTransactionIsolation(int level) throws SQLException {
  271. realConnection.setTransactionIsolation(level);
  272. }
  273. @Override
  274. public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
  275. realConnection.setTypeMap(map);
  276. }
  277. @Override
  278. public boolean isWrapperFor(Class<?> iface) throws SQLException {
  279. return realConnection.isWrapperFor(iface);
  280. }
  281. @Override
  282. public <T> T unwrap(Class<T> iface) throws SQLException {
  283. return realConnection.unwrap(iface);
  284. }
  285. }
  286. }

2.2 使用动态代理实现

代理示意图

  1. // 1、真实的代理实现应该使用InvocationHandler和Proxy两个类。
  2. // 2、代理的简单实现:见cn.itcast.proxy.a包。
  3. // 3、使用Proxy代理Connection类见:cn.itcast.proxy.b包
  4. // 以下是使用动态代理的源代码:
  5. package cn.itcast.pool;
  6. import java.lang.reflect.InvocationHandler;
  7. import java.lang.reflect.Method;
  8. import java.lang.reflect.Proxy;
  9. import java.sql.Connection;
  10. import java.sql.DriverManager;
  11. import java.util.LinkedList;
  12. /**
  13. * 数据库连接池
  14. * 使用动态代理实现
  15. * @author wangjianme
  16. */
  17. public class MyConnPool {
  18. private static String driver = "com.mysql.jdbc.Driver";
  19. private static String url= "jdbc:mysql://127.0.0.1:3306/wj?useUincode=true&characterEncoding=utf8";
  20. //使用LinkedList保存有限的连接
  21. private static LinkedList<Connection> list = new LinkedList<Connection>();
  22. static{
  23. try{
  24. Class.forName(driver);
  25. for(int i=0;i<5;i++){
  26. Connection con = DriverManager.getConnection(url,"root","root");
  27. con = MyProxy.getConn(con);//对已经生成的Connection进行代理
  28. list.addLast(con);
  29. }
  30. }catch(Exception e){
  31. throw new RuntimeException(e.getMessage(),e);
  32. }
  33. }
  34. /**
  35. * 获取一个连接
  36. * @return
  37. */
  38. public static Connection getConn(){
  39. if(list.size()>0){
  40. Connection con = list.removeFirst();
  41. return con;
  42. }else{
  43. throw new RuntimeException("已经没有可用的连接...");
  44. }
  45. }
  46. /**
  47. * 以下是动态代理类,实现执行句柄的接口
  48. * @author wangjianme
  49. */
  50. static class MyProxy implements InvocationHandler{
  51. private Object o;
  52. private MyProxy(Object o){
  53. this.o = o;
  54. }
  55. public static Connection getConn(Object o){//对传过来的对像进行代理
  56. Connection c = (Connection)Proxy.newProxyInstance(
  57. o.getClass().getClassLoader(),
  58. new Class[]{Connection.class},
  59. new MyProxy(o));//注意这个new
  60. return c;
  61. }
  62. @Override
  63. public Object invoke(Object proxy, Method method, Object[] args)
  64. throws Throwable {
  65. if(method.getName().equals("close")){
  66. System.err.println("有人在关闭连接,现在将它放回去:"+proxy);
  67. list.addLast((Connection)proxy);
  68. return null;
  69. }else{
  70. return method.invoke(o, args);
  71. }
  72. }
  73. }
  74. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注