java创建MySQL数据库连接池

注意,java接口是在win7下,MySQL是在RHEL下。

原理:

进程池的定义
1、首先定义了一个ConnectionPool类:
重要的一个定义:private Vector connections=null;//存放连接池中数据库连接的向量。
2、connections=new Vector();connections.addElement(new PooledConnection(newConnection)));

3、定义关于连接池操作的各种方法,这是重点,待补充.................
进程池的使用
1、ConnectionPool connPool=new ConnectionPool(....);//参数包括,数据库名字,用户,密码,驱动
2、coonPool.createPool();//默认创建了有10个连接的连接池
3、Connection conn=connPool.getConnetion();//从连接池中获得一个可用的连接
      Statement stmt=conn.createStatement();
      String sql="seclect * from pet";
      ResultSet rs=stmt.executeQuery(sql);
      while(rs.next()){}//没有显示查询结果
      rs.close();
      stmt.close();
      connPool.returnConnection(conn);//连接使用完后释放连接到连接池
4、connPool.closeConnectionPool();//关闭数据库连接池,耗时较大

 

示例代码:

 
  1. import java.sql.Connection;

  2. import java.sql.DatabaseMetaData;

  3. import java.sql.Driver;

  4. import java.sql.DriverManager;

  5. import java.sql.SQLException;

  6. import java.sql.Statement;

  7. import java.util.Enumeration;

  8. import java.util.Vector;

  9. public class ConnectionPool {

  10. private String jdbcDriver = ""; // 数据库驱动

  11. private String dbUrl = ""; // 数据 URL

  12. private String dbUsername = ""; // 数据库用户名

  13. private String dbPassword = ""; // 数据库用户密码

  14. private String testTable = ""; // 测试连接是否可用的测试表名,默认没有测试表

  15. private int initialConnections = 10; // 连接池的初始大小

  16. private int incrementalConnections = 5;// 连接池自动增加的大小

  17. private int maxConnections = 50; // 连接池最大的大小

  18. private Vector connections = null; // 存放连接池中数据库连接的向量 , 初始时为 null

  19. // 它中存放的对象为 PooledConnection 型

  20. /**

  21. * 构造函数

  22. *

  23. * @param jdbcDriver String JDBC 驱动类串

  24. * @param dbUrl String 数据库 URL

  25. * @param dbUsername String 连接数据库用户名

  26. * @param dbPassword String 连接数据库用户的密码

  27. *

  28. */

  29. public ConnectionPool(String jdbcDriver,String dbUrl,String dbUsername,String dbPassword) {

  30. this.jdbcDriver = jdbcDriver;

  31. this.dbUrl = dbUrl;

  32. this.dbUsername = dbUsername;

  33. this.dbPassword = dbPassword;

  34. }

  35. /**

  36. * 返回连接池的初始大小

  37. *

  38. * @return 初始连接池中可获得的连接数量

  39. */

  40. public int getInitialConnections() {

  41. return this.initialConnections;

  42. }

  43.  
  44. /**

  45. * 设置连接池的初始大小

  46. *

  47. * @param 用于设置初始连接池中连接的数量

  48. */

  49.  
  50. public void setInitialConnections(int initialConnections) {

  51. this.initialConnections = initialConnections;

  52. }

  53.  
  54. /**

  55. * 返回连接池自动增加的大小 、

  56. *

  57. * @return 连接池自动增加的大小

  58. */

  59. public int getIncrementalConnections() {

  60. return this.incrementalConnections;

  61. }

  62.  
  63. /**

  64. * 设置连接池自动增加的大小

  65. * @param 连接池自动增加的大小

  66. */

  67.  
  68. public void setIncrementalConnections(int incrementalConnections) {

  69. this.incrementalConnections = incrementalConnections;

  70. }

  71.  
  72. /**

  73. * 返回连接池中最大的可用连接数量

  74. * @return 连接池中最大的可用连接数量

  75. */

  76.  
  77. public int getMaxConnections() {

  78. return this.maxConnections;

  79. }

  80.  
  81. /**

  82. * 设置连接池中最大可用的连接数量

  83. *

  84. * @param 设置连接池中最大可用的连接数量值

  85. */

  86.  
  87. public void setMaxConnections(int maxConnections) {

  88. this.maxConnections = maxConnections;

  89. }

  90.  
  91. /**

  92. * 获取测试数据库表的名字

  93. *

  94. * @return 测试数据库表的名字

  95. */

  96.  
  97. public String getTestTable() {

  98. return this.testTable;

  99. }

  100.  
  101. /**

  102. * 设置测试表的名字

  103. * @param testTable String 测试表的名字

  104. */

  105.  
  106. public void setTestTable(String testTable) {

  107. this.testTable = testTable;

  108. }

  109.  
  110. /**

  111. *

  112. * 创建一个数据库连接池,连接池中的可用连接的数量采用类成员

  113. * initialConnections 中设置的值

  114. */

  115.  
  116. public synchronized void createPool() throws Exception {

  117. // 确保连接池没有创建

  118. // 如果连接池己经创建了,保存连接的向量 connections 不会为空

  119. if (connections != null) {

  120. return; // 如果己经创建,则返回

  121. }

  122. // 实例化 JDBC Driver 中指定的驱动类实例

  123. Driver driver = (Driver) (Class.forName(this.jdbcDriver).newInstance());

  124. DriverManager.registerDriver(driver); // 注册 JDBC 驱动程序

  125. // 创建保存连接的向量 , 初始时有 0 个元素

  126. connections = new Vector();

  127. // 根据 initialConnections 中设置的值,创建连接。

  128. createConnections(this.initialConnections);

  129. //System.out.println(" 数据库连接池创建成功! ");

  130. }

  131.  
  132. /**

  133. * 创建由 numConnections 指定数目的数据库连接 , 并把这些连接

  134. * 放入 connections 向量中

  135. *

  136. * @param numConnections 要创建的数据库连接的数目

  137. */

  138.  
  139. @SuppressWarnings("unchecked")

  140. private void createConnections(int numConnections) throws SQLException {

  141. // 循环创建指定数目的数据库连接

  142. for (int x = 0; x < numConnections; x++) {

  143. // 是否连接池中的数据库连接的数量己经达到最大?最大值由类成员 maxConnections

  144. // 指出,如果 maxConnections 为 0 或负数,表示连接数量没有限制。

  145. // 如果连接数己经达到最大,即退出。

  146. if (this.maxConnections > 0 && this.connections.size() >= this.maxConnections) {

  147. break;

  148. }

  149. //add a new PooledConnection object to connections vector

  150. // 增加一个连接到连接池中(向量 connections 中)

  151. try{

  152. connections.addElement(new PooledConnection(newConnection()));

  153. }catch(SQLException e){

  154. System.out.println(" 创建数据库连接失败! "+e.getMessage());

  155. throw new SQLException();

  156. }

  157. //System.out.println(" 数据库连接己创建 ......");

  158. }

  159. }

  160.  
  161. /**

  162. * 创建一个新的数据库连接并返回它

  163. *

  164. * @return 返回一个新创建的数据库连接

  165. */

  166.  
  167. private Connection newConnection() throws SQLException {

  168. // 创建一个数据库连接

  169. Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);

  170. // 如果这是第一次创建数据库连接,即检查数据库,获得此数据库允许支持的

  171. // 最大客户连接数目

  172. //connections.size()==0 表示目前没有连接己被创建

  173. if (connections.size() == 0) {

  174. DatabaseMetaData metaData = conn.getMetaData();

  175. int driverMaxConnections = metaData.getMaxConnections();

  176. // 数据库返回的 driverMaxConnections 若为 0 ,表示此数据库没有最大

  177. // 连接限制,或数据库的最大连接限制不知道

  178. //driverMaxConnections 为返回的一个整数,表示此数据库允许客户连接的数目

  179. // 如果连接池中设置的最大连接数量大于数据库允许的连接数目 , 则置连接池的最大

  180. // 连接数目为数据库允许的最大数目

  181. if (driverMaxConnections > 0 && this.maxConnections > driverMaxConnections) {

  182. this.maxConnections = driverMaxConnections;

  183. }

  184. }

  185. return conn; // 返回创建的新的数据库连接

  186. }

  187.  
  188. /**

  189. * 通过调用 getFreeConnection() 函数返回一个可用的数据库连接 ,

  190. * 如果当前没有可用的数据库连接,并且更多的数据库连接不能创

  191. * 建(如连接池大小的限制),此函数等待一会再尝试获取。

  192. *

  193. * @return 返回一个可用的数据库连接对象

  194. */

  195.  
  196. public synchronized Connection getConnection() throws SQLException {

  197. // 确保连接池己被创建

  198. if (connections == null) {

  199. return null; // 连接池还没创建,则返回 null

  200. }

  201. Connection conn = getFreeConnection(); // 获得一个可用的数据库连接

  202. // 如果目前没有可以使用的连接,即所有的连接都在使用中

  203. while (conn == null){

  204. // 等一会再试

  205. // System.out.println("Wait");

  206. wait(250);

  207. conn = getFreeConnection(); // 重新再试,直到获得可用的连接,如果

  208. //getFreeConnection() 返回的为 null

  209. // 则表明创建一批连接后也不可获得可用连接

  210. }

  211. return conn;// 返回获得的可用的连接

  212. }

  213.  
  214. /**

  215. * 本函数从连接池向量 connections 中返回一个可用的的数据库连接,如果

  216. * 当前没有可用的数据库连接,本函数则根据 incrementalConnections 设置

  217. * 的值创建几个数据库连接,并放入连接池中。

  218. * 如果创建后,所有的连接仍都在使用中,则返回 null

  219. * @return 返回一个可用的数据库连接

  220. */

  221. private Connection getFreeConnection() throws SQLException {

  222. // 从连接池中获得一个可用的数据库连接

  223. Connection conn = findFreeConnection();

  224. if (conn == null) {

  225. // 如果目前连接池中没有可用的连接

  226. // 创建一些连接

  227. createConnections(incrementalConnections);

  228. // 重新从池中查找是否有可用连接

  229. conn = findFreeConnection();

  230. if (conn == null) {

  231. // 如果创建连接后仍获得不到可用的连接,则返回 null

  232. return null;

  233. }

  234. }

  235. return conn;

  236. }

  237.  
  238. /**

  239. * 查找连接池中所有的连接,查找一个可用的数据库连接,

  240. * 如果没有可用的连接,返回 null

  241. *

  242. * @return 返回一个可用的数据库连接

  243. */

  244.  
  245. private Connection findFreeConnection() throws SQLException {

  246. Connection conn = null;

  247. PooledConnection pConn = null;

  248. // 获得连接池向量中所有的对象

  249. Enumeration enumerate = connections.elements();

  250. // 遍历所有的对象,看是否有可用的连接

  251. while (enumerate.hasMoreElements()) {

  252. pConn = (PooledConnection) enumerate.nextElement();

  253. if (!pConn.isBusy()) {

  254. // 如果此对象不忙,则获得它的数据库连接并把它设为忙

  255. conn = pConn.getConnection();

  256. pConn.setBusy(true);

  257. // 测试此连接是否可用

  258. if (!testConnection(conn)) {

  259. // 如果此连接不可再用了,则创建一个新的连接,

  260. // 并替换此不可用的连接对象,如果创建失败,返回 null

  261. try{

  262. conn = newConnection();

  263. }catch(SQLException e){

  264. System.out.println(" 创建数据库连接失败! "+e.getMessage());

  265. return null;

  266. }

  267. pConn.setConnection(conn);

  268. }

  269. break; // 己经找到一个可用的连接,退出

  270. }

  271. }

  272. return conn;// 返回找到到的可用连接

  273. }

  274.  
  275. /**

  276. * 测试一个连接是否可用,如果不可用,关掉它并返回 false

  277. * 否则可用返回 true

  278. *

  279. * @param conn 需要测试的数据库连接

  280. * @return 返回 true 表示此连接可用, false 表示不可用

  281. */

  282.  
  283. private boolean testConnection(Connection conn) {

  284. try {

  285. // 判断测试表是否存在

  286. if (testTable.equals("")) {

  287. // 如果测试表为空,试着使用此连接的 setAutoCommit() 方法

  288. // 来判断连接否可用(此方法只在部分数据库可用,如果不可用 ,

  289. // 抛出异常)。注意:使用测试表的方法更可靠

  290. conn.setAutoCommit(true);

  291. } else {// 有测试表的时候使用测试表测试

  292. //check if this connection is valid

  293. Statement stmt = conn.createStatement();

  294. stmt.execute("select count(*) from " + testTable);

  295. }

  296. } catch (SQLException e) {

  297. // 上面抛出异常,此连接己不可用,关闭它,并返回 false;

  298. closeConnection(conn);

  299. return false;

  300. }

  301. // 连接可用,返回 true

  302. return true;

  303. }

  304.  
  305. /**

  306. * 此函数返回一个数据库连接到连接池中,并把此连接置为空闲。

  307. * 所有使用连接池获得的数据库连接均应在不使用此连接时返回它。

  308. *

  309. * @param 需返回到连接池中的连接对象

  310. */

  311.  
  312. public void returnConnection(Connection conn) {

  313. // 确保连接池存在,如果连接没有创建(不存在),直接返回

  314. if (connections == null) {

  315. System.out.println(" 连接池不存在,无法返回此连接到连接池中 !");

  316. return;

  317. }

  318. PooledConnection pConn = null;

  319. Enumeration enumerate = connections.elements();

  320. // 遍历连接池中的所有连接,找到这个要返回的连接对象

  321. while (enumerate.hasMoreElements()) {

  322. pConn = (PooledConnection) enumerate.nextElement();

  323. // 先找到连接池中的要返回的连接对象

  324. if (conn == pConn.getConnection()) {

  325. // 找到了 , 设置此连接为空闲状态

  326. pConn.setBusy(false);

  327. break;

  328. }

  329. }

  330. }

  331.  
  332. /**

  333. * 刷新连接池中所有的连接对象

  334. *

  335. */

  336.  
  337. public synchronized void refreshConnections() throws SQLException {

  338. // 确保连接池己创新存在

  339. if (connections == null) {

  340. System.out.println(" 连接池不存在,无法刷新 !");

  341. return;

  342. }

  343. PooledConnection pConn = null;

  344. Enumeration enumerate = connections.elements();

  345. while (enumerate.hasMoreElements()) {

  346. // 获得一个连接对象

  347. pConn = (PooledConnection) enumerate.nextElement();

  348. // 如果对象忙则等 5 秒 ,5 秒后直接刷新

  349. if (pConn.isBusy()) {

  350. wait(5000); // 等 5 秒

  351. }

  352. // 关闭此连接,用一个新的连接代替它。

  353. closeConnection(pConn.getConnection());

  354. pConn.setConnection(newConnection());

  355. pConn.setBusy(false);

  356. }

  357. }

  358.  
  359. /**

  360. * 关闭连接池中所有的连接,并清空连接池。

  361. */

  362.  
  363. public synchronized void closeConnectionPool() throws SQLException {

  364. // 确保连接池存在,如果不存在,返回

  365. if (connections == null) {

  366. System.out.println(" 连接池不存在,无法关闭 !");

  367. return;

  368. }

  369. PooledConnection pConn = null;

  370. Enumeration enumerate = connections.elements();

  371. while (enumerate.hasMoreElements()) {

  372. pConn = (PooledConnection) enumerate.nextElement();

  373. // 如果忙,等 5 秒

  374. if (pConn.isBusy()) {

  375. wait(5000); // 等 5 秒

  376. }

  377. //5 秒后直接关闭它

  378. closeConnection(pConn.getConnection());

  379. // 从连接池向量中删除它

  380. connections.removeElement(pConn);

  381. }

  382. // 置连接池为空

  383. connections = null;

  384. }

  385.  
  386. /**

  387. * 关闭一个数据库连接

  388. *

  389. * @param 需要关闭的数据库连接

  390. */

  391.  
  392. private void closeConnection(Connection conn) {

  393. try {

  394. conn.close();

  395. }catch (SQLException e) {

  396. System.out.println(" 关闭数据库连接出错: "+e.getMessage());

  397. }

  398. }

  399.  
  400. /**

  401. * 使程序等待给定的毫秒数

  402. *

  403. * @param 给定的毫秒数

  404. */

  405.  
  406. private void wait(int mSeconds) {

  407. try {

  408. Thread.sleep(mSeconds);

  409. } catch (InterruptedException e) {

  410. }

  411. }

  412.  
  413. /**

  414. *

  415. * 内部使用的用于保存连接池中连接对象的类

  416. * 此类中有两个成员,一个是数据库的连接,另一个是指示此连接是否

  417. * 正在使用的标志。

  418. */

  419.  
  420. class PooledConnection {

  421. Connection connection = null;// 数据库连接

  422. boolean busy = false; // 此连接是否正在使用的标志,默认没有正在使用

  423. // 构造函数,根据一个 Connection 构告一个 PooledConnection 对象

  424. public PooledConnection(Connection connection) {

  425. this.connection = connection;

  426. }

  427. // 返回此对象中的连接

  428. public Connection getConnection() {

  429. return connection;

  430. }

  431. // 设置此对象的,连接

  432. public void setConnection(Connection connection) {

  433. this.connection = connection;

  434. }

  435. // 获得对象连接是否忙

  436. public boolean isBusy() {

  437. return busy;

  438. }

  439. // 设置对象的连接正在忙

  440. public void setBusy(boolean busy) {

  441. this.busy = busy;

  442. }

  443. }

  444.  
  445. }


测试代码:

 
  1. import java.sql.Connection;

  2. import java.sql.DriverManager;

  3. import java.sql.ResultSet;

  4. import java.sql.SQLException;

  5. import java.sql.Statement;

  6. public class ConnecttionPoolTest {

  7. /**

  8. * @param args

  9. * @throws Exception

  10. */

  11. public static void main(String[] args) throws Exception {

  12.    // TODO Auto-generated method stub

  13.     try {

  14.    //创建数据库连接库对象

  15.    ConnectionPool connPool

  16.         = new ConnectionPool("com.mysql.jdbc.Driver"

  17.                                             ,"jdbc:mysql://192.168.1.19:3306/test"

  18.                                             ,"test"

  19.                                             ,"root");

  20.    //新建数据库连接库

  21.    connPool.createPool();

  22.    //SQL测试语句

  23.    String sql="Select * from pet";  

  24.    //设定程序运行起始时间

  25.    long start = System.currentTimeMillis();

  26.    //循环测试100次数据库连接

  27.    for (int i = 0; i < 3; i++)

  28.        {

  29.         Connection conn = connPool.getConnection(); //从连接库中获取一个可用的连接

  30.         Statement stmt = conn.createStatement();

  31.         ResultSet rs = stmt.executeQuery(sql);

  32.         while (rs.next())

  33.         {

  34.             String name=rs.getString("name");

  35.             System.out.println("查询结果"+name);  

  36.         }

  37.         rs.close();

  38.              stmt.close();

  39.              connPool.returnConnection(conn);             //连接使用完后释放连接到连接池

  40.          }

  41.    System.out.println("经过100次的循环调用,使用连接池花费的时间:" + (System.currentTimeMillis() - start) + "ms");

  42.         //connPool.refreshConnections();//刷新数据库连接池中所有连接,即不管连接是否正在运行,都把所有连接都释放并放回到连接池。注意:这个耗时比较大。

  43.          connPool.closeConnectionPool();//关闭数据库连接池。注意:这个耗时比较大。

  44.         //设定程序运行起始时间

  45.          start = System.currentTimeMillis();

  46.          //导入驱动

  47.          Class.forName("com.mysql.jdbc.Driver");

  48.          for (int i = 0; i < 100; i++)

  49.       {

  50.          //创建连接

  51.         Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.1.19:3306/test","test","root");

  52.              Statement stmt = conn.createStatement();

  53.              ResultSet rs = stmt.executeQuery(sql);

  54.              while (rs.next()) {}

  55.              rs.close();

  56.              stmt.close();

  57.              conn.close();//关闭连接

  58.         }

  59.         System.out.println("经过100次的循环调用,不使用连接池花费的时间:" + (System.currentTimeMillis() - start) + "ms");

  60.     }

  61.     catch (SQLException e)

  62.     {  

  63.      e.printStackTrace();  

  64.     }

  65.     catch (ClassNotFoundException e)

  66.     {  

  67.          e.printStackTrace();  

  68.     }  

  69. }

  70. }


运行结果:

猜你喜欢

转载自blog.csdn.net/yangzhengjianglove/article/details/81233508