數據庫鏈接池(JDBC、DBCP、C3P0三種實現)

今天工做中遇到新的需求,要將項目DBCP鏈接切換到本身的ZDAL,因而花了點時間研究數據庫鏈接池。html

項目Github地址:java

 

轉自:http://www.cnblogs.com/xdp-gacl/p/4002804.htmlmysql

-------sql

1、應用程序直接獲取數據庫鏈接的缺點

  用戶每次請求都須要向數據庫得到連接,而數據庫建立鏈接一般須要消耗相對較大的資源,建立時間也較長。假設網站一天10萬訪問量,數據庫服務器就須要建立10萬次鏈接,極大的浪費數據庫的資源,而且極易形成數據庫服務器內存溢出、拓機。以下圖所示:數據庫

  

2、使用數據庫鏈接池優化程序性能

2.一、數據庫鏈接池的基本概念

  數據庫鏈接是一種關鍵的有限的昂貴的資源,這一點在多用戶的網頁應用程序中體現的尤其突出.對數據庫鏈接的管理能顯著影響到整個應用程序的伸縮性和健壯性,影響到程序的性能指標.數據庫鏈接池正式針對這個問題提出來的.數據庫鏈接池負責分配,管理和釋放數據庫鏈接,它容許應用程序重複使用一個現有的數據庫鏈接,而不是從新創建一個。以下圖所示:apache

  

       數據庫鏈接池在初始化時將建立必定數量的數據庫鏈接放到鏈接池中, 這些數據庫鏈接的數量是由最小數據庫鏈接數來設定的.不管這些數據庫鏈接是否被使用,鏈接池都將一直保證至少擁有這麼多的鏈接數量.鏈接池的最大數據庫鏈接數量限定了這個鏈接池能佔有的最大鏈接數,當應用程序向鏈接池請求的鏈接數超過最大鏈接數量時,這些請求將被加入到等待隊列中.編程

       數據庫鏈接池的最小鏈接數和最大鏈接數的設置要考慮到如下幾個因素:服務器

  1. 最小鏈接數:是鏈接池一直保持的數據庫鏈接,因此若是應用程序對數據庫鏈接的使用量不大,將會有大量的數據庫鏈接資源被浪費.
  2. 最大鏈接數:是鏈接池能申請的最大鏈接數,若是數據庫鏈接請求超過次數,後面的數據庫鏈接請求將被加入到等待隊列中,這會影響之後的數據庫操做
  3. 若是最小鏈接數與最大鏈接數相差很大:那麼最早鏈接請求將會獲利,以後超過最小鏈接數量的鏈接請求等價於創建一個新的數據庫鏈接.不過,這些大於最小鏈接數的數據庫鏈接在使用完不會立刻被釋放,他將被放到鏈接池中等待重複使用或是空間超時後被釋放.

2.二、編寫數據庫鏈接池

  編寫鏈接池需實現java.sql.DataSource接口。DataSource接口中定義了兩個重載的getConnection方法:oracle

  • Connection getConnection()
  • Connection getConnection(String username, String password)

  實現DataSource接口,並實現鏈接池功能的步驟:app

  1. 在DataSource構造函數中批量建立與數據庫的鏈接,並把建立的鏈接加入LinkedList對象中。
  2. 實現getConnection方法,讓getConnection方法每次調用時,從LinkedList中取一個Connection返回給用戶。
  3. 當用戶使用完Connection,調用Connection.close()方法時,Collection對象應保證將本身返回到LinkedList中,而不要把conn還給數據庫。Collection保證將本身返回到LinkedList中是此處編程的難點

 數據庫鏈接池核心代碼

  使用動態代理技術構建鏈接池中的connection

 

1 proxyConn = (Connection) Proxy.newProxyInstance(this.getClass()
 2             .getClassLoader(), conn.getClass().getInterfaces(),
 3             new InvocationHandler() {
 4         //此處爲內部類,當close方法被調用時將conn還回池中,其它方法直接執行
 5             public Object invoke(Object proxy, Method method,
 6                       Object[] args) throws Throwable {
 7                 if (method.getName().equals("close")) {
 8                     pool.addLast(conn);
 9                     return null;
10             }
11             return method.invoke(conn, args);
12         }
13     });

 

數據庫鏈接池編寫範例:

 

1 package me.gacl.demo;
  2 
  3 import java.io.InputStream;
  4 import java.io.PrintWriter;
  5 import java.lang.reflect.InvocationHandler;
  6 import java.lang.reflect.Method;
  7 import java.lang.reflect.Proxy;
  8 import java.sql.Connection;
  9 import java.sql.DriverManager;
 10 import java.sql.SQLException;
 11 import java.util.LinkedList;
 12 import java.util.Properties;
 13 import javax.sql.DataSource;
 14 
 15 /**
 16 * @ClassName: JdbcPool
 17 * @Description:編寫數據庫鏈接池
 18 * @author: 孤傲蒼狼
 19 * @date: 2014-9-30 下午11:07:23
 20 *
 21 */ 
 22 public class JdbcPool implements DataSource{
 23 
 24     /**
 25     * @Field: listConnections
 26     *         使用LinkedList集合來存放數據庫連接,
 27     *        因爲要頻繁讀寫List集合,因此這裏使用LinkedList存儲數據庫鏈接比較合適
 28     */ 
 29     private static LinkedList<Connection> listConnections = new LinkedList<Connection>();
 30     
 31     static{
 32         //在靜態代碼塊中加載db.properties數據庫配置文件
 33         InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
 34         Properties prop = new Properties();
 35         try {
 36             prop.load(in);
 37             String driver = prop.getProperty("driver");
 38             String url = prop.getProperty("url");
 39             String username = prop.getProperty("username");
 40             String password = prop.getProperty("password");
 41             //數據庫鏈接池的初始化鏈接數大小
 42             int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize"));
 43             //加載數據庫驅動
 44             Class.forName(driver);
 45             for (int i = 0; i < jdbcPoolInitSize; i++) {
 46                 Connection conn = DriverManager.getConnection(url, username, password);
 47                 System.out.println("獲取到了連接" + conn);
 48                 //將獲取到的數據庫鏈接加入到listConnections集合中,listConnections集合此時就是一個存放了數據庫鏈接的鏈接池
 49                 listConnections.add(conn);
 50             }
 51             
 52         } catch (Exception e) {
 53             throw new ExceptionInInitializerError(e);
 54         }
 55     }
 56     
 57     @Override
 58     public PrintWriter getLogWriter() throws SQLException {
 59         // TODO Auto-generated method stub
 60         return null;
 61     }
 62 
 63     @Override
 64     public void setLogWriter(PrintWriter out) throws SQLException {
 65         // TODO Auto-generated method stub
 66         
 67     }
 68 
 69     @Override
 70     public void setLoginTimeout(int seconds) throws SQLException {
 71         // TODO Auto-generated method stub
 72         
 73     }
 74 
 75     @Override
 76     public int getLoginTimeout() throws SQLException {
 77         // TODO Auto-generated method stub
 78         return 0;
 79     }
 80 
 81     @Override
 82     public <T> T unwrap(Class<T> iface) throws SQLException {
 83         // TODO Auto-generated method stub
 84         return null;
 85     }
 86 
 87     @Override
 88     public boolean isWrapperFor(Class<?> iface) throws SQLException {
 89         // TODO Auto-generated method stub
 90         return false;
 91     }
 92 
 93     /* 獲取數據庫鏈接
 94      * @see javax.sql.DataSource#getConnection()
 95      */
 96     @Override
 97     public Connection getConnection() throws SQLException {
 98         //若是數據庫鏈接池中的鏈接對象的個數大於0
 99         if (listConnections.size()>0) {
100             //從listConnections集合中獲取一個數據庫鏈接
101             final Connection conn = listConnections.removeFirst();
102             System.out.println("listConnections數據庫鏈接池大小是" + listConnections.size());
103             //返回Connection對象的代理對象
104             return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){
105                 @Override
106                 public Object invoke(Object proxy, Method method, Object[] args)
107                         throws Throwable {
108                     if(!method.getName().equals("close")){
109                         return method.invoke(conn, args);
110                     }else{
111                         //若是調用的是Connection對象的close方法,就把conn還給數據庫鏈接池
112                         listConnections.add(conn);
113                         System.out.println(conn + "被還給listConnections數據庫鏈接池了!!");
114                         System.out.println("listConnections數據庫鏈接池大小爲" + listConnections.size());
115                         return null;
116                     }
117                 }
118             });
119         }else {
120             throw new RuntimeException("對不起,數據庫忙");
121         }
122     }
123 
124     @Override
125     public Connection getConnection(String username, String password)
126             throws SQLException {
127         return null;
128     }
129 }

 

 db.properties配置文件以下:

1 driver=com.mysql.jdbc.Driver
2 url=jdbc:mysql://localhost:3306/jdbcStudy
3 username=root
4 password=XDP
5 
6 jdbcPoolInitSize=10

寫一個JdbcUtil測試數據庫鏈接池

 

1 package me.gacl.utils;
 2 
 3 import java.sql.Connection;
 4 import java.sql.ResultSet;
 5 import java.sql.SQLException;
 6 import java.sql.Statement;
 7 import me.gacl.demo.JdbcPool;
 8 
 9 public class JdbcUtil {
10     
11     /**
12     * @Field: pool
13     *          數據庫鏈接池
14     */ 
15     private static JdbcPool pool = new JdbcPool();
16     
17     /**
18     * @Method: getConnection
19     * @Description: 從數據庫鏈接池中獲取數據庫鏈接對象
20     * @Anthor:孤傲蒼狼
21     * @return Connection數據庫鏈接對象
22     * @throws SQLException
23     */ 
24     public static Connection getConnection() throws SQLException{
25         return pool.getConnection();
26     }
27     
28     /**
29     * @Method: release
30     * @Description: 釋放資源,
31     * 釋放的資源包括Connection數據庫鏈接對象,負責執行SQL命令的Statement對象,存儲查詢結果的ResultSet對象
32     * @Anthor:孤傲蒼狼
33     *
34     * @param conn
35     * @param st
36     * @param rs
37     */ 
38     public static void release(Connection conn,Statement st,ResultSet rs){
39         if(rs!=null){
40             try{
41                 //關閉存儲查詢結果的ResultSet對象
42                 rs.close();
43             }catch (Exception e) {
44                 e.printStackTrace();
45             }
46             rs = null;
47         }
48         if(st!=null){
49             try{
50                 //關閉負責執行SQL命令的Statement對象
51                 st.close();
52             }catch (Exception e) {
53                 e.printStackTrace();
54             }
55         }
56         
57         if(conn!=null){
58             try{
59                 //關閉Connection數據庫鏈接對象
60                 conn.close();
61             }catch (Exception e) {
62                 e.printStackTrace();
63             }
64         }
65     }
66 }

 

 3、開源數據庫鏈接池

  如今不少WEB服務器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的實現,即鏈接池的實現。一般咱們把DataSource的實現,按其英文含義稱之爲數據源,數據源中都包含了數據庫鏈接池的實現。
  也有一些開源組織提供了數據源的獨立實現:

  • DBCP 數據庫鏈接池
  • C3P0 數據庫鏈接池

  在使用了數據庫鏈接池以後,在項目的實際開發中就不須要編寫鏈接數據庫的代碼了,直接從數據源得到數據庫的鏈接。

3.一、DBCP數據源

  DBCP 是 Apache 軟件基金組織下的開源鏈接池實現,要使用DBCP數據源,須要應用程序應在系統中增長以下兩個 jar 文件:

  • Commons-dbcp.jar:鏈接池的實現
  • Commons-pool.jar:鏈接池實現的依賴庫

  Tomcat 的鏈接池正是採用該鏈接池來實現的。該數據庫鏈接池既能夠與應用服務器整合使用,也可由應用程序獨立使用。

3.二、在應用程序中加入dbcp鏈接池

  1.導入相關jar包
        commons-dbcp-1.2.2.jar、commons-pool.jar
  二、在類目錄下加入dbcp的配置文件:dbcpconfig.properties

    dbcpconfig.properties的配置信息以下:

 

1 #鏈接設置
 2 driverClassName=com.mysql.jdbc.Driver
 3 url=jdbc:mysql://localhost:3306/jdbcstudy
 4 username=root
 5 password=XDP
 6 
 7 #<!-- 初始化鏈接 -->
 8 initialSize=10
 9 
10 #最大鏈接數量
11 maxActive=50
12 
13 #<!-- 最大空閒鏈接 -->
14 maxIdle=20
15 
16 #<!-- 最小空閒鏈接 -->
17 minIdle=5
18 
19 #<!-- 超時等待時間以毫秒爲單位 6000毫秒/1000等於60秒 -->
20 maxWait=60000
21 
22 
23 #JDBC驅動創建鏈接時附帶的鏈接屬性屬性的格式必須爲這樣:[屬性名=property;] 
24 #注意:"user" 與 "password" 兩個屬性會被明確地傳遞,所以這裏不須要包含他們。
25 connectionProperties=useUnicode=true;characterEncoding=UTF8
26 
27 #指定由鏈接池所建立的鏈接的自動提交(auto-commit)狀態。
28 defaultAutoCommit=true
29 
30 #driver default 指定由鏈接池所建立的鏈接的只讀(read-only)狀態。
31 #若是沒有設置該值,則「setReadOnly」方法將不被調用。(某些驅動並不支持只讀模式,如:Informix)
32 defaultReadOnly=
33 
34 #driver default 指定由鏈接池所建立的鏈接的事務級別(TransactionIsolation)。
35 #可用值爲下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
36 defaultTransactionIsolation=READ_UNCOMMITTED

 

  以下圖所示:

  

  三、在獲取數據庫鏈接的工具類(如jdbcUtils)的靜態代碼塊中建立池

 

1 package me.gacl.util;
 2 
 3 import java.io.InputStream;
 4 import java.sql.Connection;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 import java.sql.Statement;
 8 import java.util.Properties;
 9 import javax.sql.DataSource;
10 import org.apache.commons.dbcp.BasicDataSourceFactory;
11 
12 /**
13 * @ClassName: JdbcUtils_DBCP
14 * @Description: 數據庫鏈接工具類
15 * @author: 孤傲蒼狼
16 * @date: 2014-10-4 下午6:04:36
17 *
18 */ 
19 public class JdbcUtils_DBCP {
20     /**
21      * 在java中,編寫數據庫鏈接池需實現java.sql.DataSource接口,每一種數據庫鏈接池都是DataSource接口的實現
22      * DBCP鏈接池就是java.sql.DataSource接口的一個具體實現
23      */
24     private static DataSource ds = null;
25     //在靜態代碼塊中建立數據庫鏈接池
26     static{
27         try{
28             //加載dbcpconfig.properties配置文件
29             InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
30             Properties prop = new Properties();
31             prop.load(in);
32             //建立數據源
33             ds = BasicDataSourceFactory.createDataSource(prop);
34         }catch (Exception e) {
35             throw new ExceptionInInitializerError(e);
36         }
37     }
38     
39     /**
40     * @Method: getConnection
41     * @Description: 從數據源中獲取數據庫鏈接
42     * @Anthor:孤傲蒼狼
43     * @return Connection
44     * @throws SQLException
45     */ 
46     public static Connection getConnection() throws SQLException{
47         //從數據源中獲取數據庫鏈接
48         return ds.getConnection();
49     }
50     
51     /**
52     * @Method: release
53     * @Description: 釋放資源,
54     * 釋放的資源包括Connection數據庫鏈接對象,負責執行SQL命令的Statement對象,存儲查詢結果的ResultSet對象
55     * @Anthor:孤傲蒼狼
56     *
57     * @param conn
58     * @param st
59     * @param rs
60     */ 
61     public static void release(Connection conn,Statement st,ResultSet rs){
62         if(rs!=null){
63             try{
64                 //關閉存儲查詢結果的ResultSet對象
65                 rs.close();
66             }catch (Exception e) {
67                 e.printStackTrace();
68             }
69             rs = null;
70         }
71         if(st!=null){
72             try{
73                 //關閉負責執行SQL命令的Statement對象
74                 st.close();
75             }catch (Exception e) {
76                 e.printStackTrace();
77             }
78         }
79         
80         if(conn!=null){
81             try{
82                 //將Connection鏈接對象還給數據庫鏈接池
83                 conn.close();
84             }catch (Exception e) {
85                 e.printStackTrace();
86             }
87         }
88     }
89 }

 

  測試DBCP數據源

 

1 package me.gacl.test;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.ResultSet;
 6 import org.junit.Test;
 7 import me.gacl.util.JdbcUtils_DBCP;
 8 
 9 public class DataSourceTest {
10     
11     @Test
12     public void dbcpDataSourceTest() {
13         Connection conn = null;
14         PreparedStatement st = null;
15         ResultSet rs = null;
16         try{
17             //獲取數據庫鏈接
18             conn = JdbcUtils_DBCP.getConnection();
19             String sql = "insert into test1(name) values(?)";
20             st = conn.prepareStatement(sql);
21             st.setString(1, "gacl");
22             st.executeUpdate();
23             //獲取數據庫自動生成的主鍵
24             rs = st.getGeneratedKeys();
25             if(rs.next()){
26                 System.out.println(rs.getInt(1));
27             }
28         }catch (Exception e) {
29             e.printStackTrace();
30         }finally{
31             //釋放資源
32             JdbcUtils_DBCP.release(conn, st, rs);
33         }
34     }
35 }

 

 3.三、C3P0數據源

  C3P0是一個開源的JDBC鏈接池,它實現了數據源和JNDI綁定,支持JDBC3規範和JDBC2的標準擴展。目前使用它的開源項目有Hibernate,Spring等。C3P0數據源在項目開發中使用得比較多。

  c3p0與dbcp區別

  1. dbcp沒有自動回收空閒鏈接的功能
  2. c3p0有自動回收空閒鏈接功能

3.四、在應用程序中加入C3P0鏈接池

  1.導入相關jar包
       c3p0-0.9.2-pre1.jar、mchange-commons-0.2.jar,若是操做的是Oracle數據庫,那麼還須要導入c3p0-oracle-thin-extras-0.9.2-pre1.jar
  二、在類目錄下加入C3P0的配置文件:c3p0-config.xml

    c3p0-config.xml的配置信息以下:

 

1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!--
 3 c3p0-config.xml必須位於類路徑下面
 4 private static ComboPooledDataSource ds;
 5 static{
 6     try {
 7         ds = new ComboPooledDataSource("MySQL");
 8     } catch (Exception e) {
 9         throw new ExceptionInInitializerError(e);
10     }
11 }
12 -->
13 
14 <c3p0-config>
15     <!--
16     C3P0的缺省(默認)配置,
17     若是在代碼中「ComboPooledDataSource ds = new ComboPooledDataSource();」這樣寫就表示使用的是C3P0的缺省(默認)配置信息來建立數據源
18     -->
19     <default-config>
20         <property name="driverClass">com.mysql.jdbc.Driver</property>
21         <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy</property>
22         <property name="user">root</property>
23         <property name="password">XDP</property>
24         
25         <property name="acquireIncrement">5</property>
26         <property name="initialPoolSize">10</property>
27         <property name="minPoolSize">5</property>
28         <property name="maxPoolSize">20</property>
29     </default-config>
30 
31     <!--
32     C3P0的命名配置,
33     若是在代碼中「ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");」這樣寫就表示使用的是name是MySQL的配置信息來建立數據源
34     -->
35     <named-config name="MySQL">
36         <property name="driverClass">com.mysql.jdbc.Driver</property>
37         <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy</property>
38         <property name="user">root</property>
39         <property name="password">XDP</property>
40         
41         <property name="acquireIncrement">5</property>
42         <property name="initialPoolSize">10</property>
43         <property name="minPoolSize">5</property>
44         <property name="maxPoolSize">20</property>
45     </named-config>
46 
47 </c3p0-config>

 

  以下圖所示:

  

  三、在獲取數據庫鏈接的工具類(如jdbcUtils)的靜態代碼塊中建立池

 

1 package me.gacl.util;
 2 
 3 import java.sql.Connection;
 4 import java.sql.ResultSet;
 5 import java.sql.SQLException;
 6 import java.sql.Statement;
 7 import com.mchange.v2.c3p0.ComboPooledDataSource;
 8 
 9 /**
10 * @ClassName: JdbcUtils_C3P0
11 * @Description: 數據庫鏈接工具類
12 * @author: 孤傲蒼狼
13 * @date: 2014-10-4 下午6:04:36
14 *
15 */ 
16 public class JdbcUtils_C3P0 {
17     
18     private static ComboPooledDataSource ds = null;
19     //在靜態代碼塊中建立數據庫鏈接池
20     static{
21         try{
22             //經過代碼建立C3P0數據庫鏈接池
23             /*ds = new ComboPooledDataSource();
24             ds.setDriverClass("com.mysql.jdbc.Driver");
25             ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy");
26             ds.setUser("root");
27             ds.setPassword("XDP");
28             ds.setInitialPoolSize(10);
29             ds.setMinPoolSize(5);
30             ds.setMaxPoolSize(20);*/
31             
32             //經過讀取C3P0的xml配置文件建立數據源,C3P0的xml配置文件c3p0-config.xml必須放在src目錄下
33             //ds = new ComboPooledDataSource();//使用C3P0的默認配置來建立數據源
34             ds = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置來建立數據源
35             
36         }catch (Exception e) {
37             throw new ExceptionInInitializerError(e);
38         }
39     }
40     
41     /**
42     * @Method: getConnection
43     * @Description: 從數據源中獲取數據庫鏈接
44     * @Anthor:孤傲蒼狼
45     * @return Connection
46     * @throws SQLException
47     */ 
48     public static Connection getConnection() throws SQLException{
49         //從數據源中獲取數據庫鏈接
50         return ds.getConnection();
51     }
52     
53     /**
54     * @Method: release
55     * @Description: 釋放資源,
56     * 釋放的資源包括Connection數據庫鏈接對象,負責執行SQL命令的Statement對象,存儲查詢結果的ResultSet對象
57     * @Anthor:孤傲蒼狼
58     *
59     * @param conn
60     * @param st
61     * @param rs
62     */ 
63     public static void release(Connection conn,Statement st,ResultSet rs){
64         if(rs!=null){
65             try{
66                 //關閉存儲查詢結果的ResultSet對象
67                 rs.close();
68             }catch (Exception e) {
69                 e.printStackTrace();
70             }
71             rs = null;
72         }
73         if(st!=null){
74             try{
75                 //關閉負責執行SQL命令的Statement對象
76                 st.close();
77             }catch (Exception e) {
78                 e.printStackTrace();
79             }
80         }
81         
82         if(conn!=null){
83             try{
84                 //將Connection鏈接對象還給數據庫鏈接池
85                 conn.close();
86             }catch (Exception e) {
87                 e.printStackTrace();
88             }
89         }
90     }
91 }

 

  測試C3P0數據源

 

1 package me.gacl.test;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.ResultSet;
 6 import org.junit.Test;
 7 import me.gacl.util.JdbcUtils_C3P0;
 8 import me.gacl.util.JdbcUtils_DBCP;
 9 
10 public class DataSourceTest {
11     
12     @Test
13     public void c3p0DataSourceTest() {
14         Connection conn = null;
15         PreparedStatement st = null;
16         ResultSet rs = null;
17         try{
18             //獲取數據庫鏈接
19             conn = JdbcUtils_C3P0.getConnection();
20             String sql = "insert into test1(name) values(?)";
21             st = conn.prepareStatement(sql);
22             st.setString(1, "gacl");
23             st.executeUpdate();
24             //獲取數據庫自動生成的主鍵
25             rs = st.getGeneratedKeys();
26             if(rs.next()){
27                 System.out.println(rs.getInt(1));
28             }
29         }catch (Exception e) {
30             e.printStackTrace();
31         }finally{
32             //釋放資源
33             JdbcUtils_C3P0.release(conn, st, rs);
34         }
35     }
36 }
相關文章
相關標籤/搜索