官术网_书友最值得收藏!

7.5 JDBC高級應用——數據庫連接池

當編寫對于數據庫的訪問不是很頻繁的應用程序時,可以在需要訪問數據庫時創建一個新連接,用完后就關閉它,這樣做不會帶來什么明顯的性能上的開銷。但是對于一個復雜的數據庫應用,情況就完全不同了,頻繁地建立、關閉連接,會極大地降低該應用程序的性能。

7.5.1 數據庫連接池簡介

為了避免頻繁的建立和關閉數據庫,開發人員可以通過建立一個數據庫連接池和一套管理策略來達到連接資源的共享,使得對于數據庫的連接高效、安全。

對于共享資源,有一個很著名的設計模式:資源池。該模式正是為了解決資源頻繁分配、釋放所造成的問題。把該模式應用到數據庫連接管理領域,就是建立一個數據庫連接池,提供一套高效的連接分配、使用策略,最終目標是實現連接的高效、安全的復用。

數據庫連接池的基本原理是在內部對象池中,維護一定數量的數據庫連接,并對外暴露數據庫連接獲取和返回方法。如圖7.27所示,當程序中需要建立數據庫連接時,只需從內存中獲取一個數據庫連接,而不是新建一個數據庫連接,在使用完畢后,只需放回內存即可。對于連接的建立和斷開都由連接池自己管理。

圖7.27 數據庫連接池原理

綜上所述,使用數據庫連接池具有如下特點。

● 資源重用:為了避免頻繁的創建、釋放數據庫連接,實現了數據庫連接的重用。

● 高效的系統響應:數據庫連接池在初始化過程中,一般就會創建若干個數據庫連接存儲在池中備用,所以具有高效的效率。

● 統一的連接管理:對于連接數目的創建、斷開、管理和關閉等操作都是由數據庫連接池統一管理。

7.5.2 數據庫連接池原理

通過上一節可以知道數據庫連接池的簡單概念,這一節將通過一個簡單的實例來演示如何實現數據庫連接池和使用數據庫連接池后的效果,在該實例中連接池是通過JDBC驅動程序來實現連接的,具體步驟如下:

01 首先創建一個名為connectionpooling的Java項目。

02 接著創建兩個文件,其中ConnectionPool.java文件實現數據庫連接池程序,具體內容如下:

      //******* ConnectionPool.java **************
      public class ConnectionPool {
        private Vector<Connection> pool;
        private String url;
        private String username;
        private String password;
        private String driverClassName;
        private int poolSize=1;            //連接池的大小,也就是連接池中有多少個數據庫連接
        private static ConnectionPool instance = null;
        //私有的構造方法,禁止外部創建本類的對象,要想獲得本類的對象,需要通過
        //<code>getIstance</code>方法
        private ConnectionPool() {
              init();
        }
        //連接池初始化方法,讀取屬性文件的內容建立連接池中的初始連接
        private void init() {
              pool = new Vector<Connection>(poolSize);
              readConfig();
              addConnection();
        }
        //返回連接到連接池中
        public synchronized void release(Connection conn) {
              pool.add(conn);
        }
        //關閉連接池中的所有數據庫連接
        public synchronized void closePool() {
              for (int i = 0; i < pool.size(); i++) {
                try {
                    ((Connection) pool.get(i)).close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                pool.remove(i);
              }
        }
        //返回當前連接池的一個對象
        public static ConnectionPool getInstance() {
              if (instance == null) {
                instance = new ConnectionPool();
              }
              return instance;
        }
      //返回連接池中的一個數據庫連接
      public synchronized Connection getConnection() {
          if (pool.size() > 0) {
              Connection conn = pool.get(0);
              pool.remove(conn);
              return conn;
          } else {
              return null;
          }
      }
      //在連接池中創建初始設置的的數據庫連接
      private void addConnection() {
          Connection conn = null;
          for (int i = 0; i < poolSize; i++) {
              try {
                  Class.forName(driverClassName);
                  conn = java.sql.DriverManager.getConnection(url, username, password);
                  pool.add(conn);
              } catch (ClassNotFoundException e) {
                  e.printStackTrace();
              } catch (SQLException e) {
                  e.printStackTrace();
              }
          }
      }
      //讀取設置連接池的屬性文件
      private void readConfig() {
          try {
              String path = System.getProperty("user.dir") + "\\dbpool.properties";
              FileInputStream is = new FileInputStream(path);
              Properties props = new Properties();
              props.load(is);
              this.driverClassName = props.getProperty("driverClassName");
              this.username = props.getProperty("username");
              this.password = props.getProperty("password");
              this.url = props.getProperty("url");
              this.poolSize = Integer.parseInt(props.getProperty("poolSize"));
          } catch (Exception e) {
              e.printStackTrace();
              System.err.println("讀取屬性文件出錯. ");
          }
      }
      }

代碼說明:

在具體開發程序時并不需要程序員自己實現數據庫連接池,因為許多公司或組織已經把性能更好的數據庫連接池組件集成到自己的軟件中了,程序員在需要使用數據庫連接池時只需要簡單配置一下即可。

另一個ConnectionPoolTest.java文件用來測試連接池程序,具體內容如下:

      //******* ConnectionPoolTest.java **************
      public class ConnectionPoolTest {
        public static void main(String[] args) throws Exception {
              String sql="select*from student";                    //定義SQL語句
              long start=System.currentTimeMillis();               //定義一個時間變量
              ConnectionPool pool=null;                      //定義一個數據庫連接池變量
              for (int i = 0; i < 100; i++) {
                pool=ConnectionPool.getInstance();                //初始化數據庫連接池
                Connection conn=pool.getConnection();              //獲取連接對象
                Statement stmt=conn.createStatement();             //創建陳述對象
                ResultSet rs=stmt.executeQuery(sql);               //執行SQL語句
                while (rs.next()) {
                }
                rs.close();                                 //關閉數據集
                stmt.close();                               //關閉陳述對象
                pool.release(conn);                               //返回連接對象
              }
              pool.closePool();                                   //關閉數據庫連接池
              System.out.println("經過100次的循環調用,使用連接池花費的時間:" + (System.
              currentTimeMillis() - start) + "ms\n");
              String hostName="127.0.0.1";                        //安裝數據庫的計算機
              String driverClass="com.mysql.jdbc.Driver";         //加載mysql數據庫驅動程序
              String url="jdbc:mysql://hostname:3306/testmysql";   //數據庫URL
              String user="root";                                 //用戶名
              String password="root";                              //用戶密碼
              start = System.currentTimeMillis();
              for (int i = 0; i < 100; i++) {
                Class.forName(driverClass);                       //加載數據庫驅動
                Connection conn = DriverManager.getConnection(url, user, password);
                Statement stmt=conn.createStatement();             //創建陳述對象
                ResultSet rs=stmt.executeQuery(sql);               //執行SQL語句
                while (rs.next()) {
                }
                rs.close();
                stmt.close();
                conn.close();
              }
              System.out.println("經過100次的循環調用,不使用連接池花費的時間:" + (System.
              currentTimeMillis() - start) + "ms");
        }
      }

代碼說明:

在上述代碼中第一個for循環中通過數據庫連接池來實現100次數據庫的連接和關閉,而第二個for循環中通過直接調用JDBC驅動程序來實現100次數據庫的連接和關閉。

03 在connectionpooling項目中創建一個名為dbpool.properties的屬性文件,用來配置數據庫連接池連接數據庫的信息,具體內容如下:

      //******* dbpool.properties **************
      driverClassName=oracle.jdbc.driver.OracleDriver         //加載數據庫驅動程序
      username=scott                                           //用戶名
      password=root                                            //用戶密碼
      url=jdbc:oracle:thin:@localhost:1521:orcll               //數據庫URL
      poolSize=10                                              //數據庫連接數目

04 編譯和運行ConnectionPoolTest程序后,其運行結果如圖7.28所示。

圖7.28 運行結果

注意:雖然測試程序的運行結果會根據具體的計算機性能顯示的時間不一樣,但是不使用數據庫連接池花費的時間,基本上是使用數據庫連接池的n倍。

7.5.3 配置和使用服務器Tomcat 7連接池

在開發具體項目時編寫數據庫連接池是沒有必要,因為現在已經存在許多數據庫連接池的現成組件,只需要配置一下就可以使用。而且現在許多應用服務器都已經內置了數據庫連接池,如Tomcat服務器、Jboss服務器和WebLogic服務器等。

之所以能夠調用已經內置好的數據庫連接池,是因為JavaEE支持JNDI。JNDI的英文全稱是Java Naming and Directory Interface,中文意思為“Java命名和目錄服務接口”。JNDI向應用程序提供了一個查詢和使用遠程服務的機制。

數據源的使用方法如下:

01 在Tomcat 7中配置數據源,可以直接在server.xml文件中配置,也可以在每個項目單獨的XML文件中配置,示例代碼如下:

      <Resource name="JDBC/opendb" auth="Container"  type="javax.sql.DataSource" factory="org.
  apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
      driverClassName="org.postgresql.Driver" url="JDBC:postgresql://localhost/testDb" username="sa"
  password="sa" maxActive="10000"
      maxIdle="10000" maxWait="10000"  removeAbandoned="true" removeAbandonedTimeout="10"
  logAbandoned="true"
      />

02 在web.xml文件中添加如下配置:

      <resource-ref>
          <res-ref-name>JDBC/opendb</res-ref-name>
          <res-type>javax.sql.DataSource</res-type>
          <res-auth>Container</res-auth>
      </resource-ref>

03 在程序中可以使用如下代碼獲取數據源和數據庫連接:

      Connection conn = ((DataSource) new InitialContext().lookup("java:/comp/env/jdbc/opendb")).
    getConnection();
主站蜘蛛池模板: 徐汇区| 安新县| 崇仁县| 西贡区| 麻城市| 方城县| 江阴市| 辽宁省| 卓尼县| 兴仁县| 平邑县| 柳林县| 罗平县| 淮安市| 馆陶县| 铜川市| 保康县| 台中市| 沾化县| 蒙城县| 东安县| 巴楚县| 河津市| 泌阳县| 册亨县| 岗巴县| 辉南县| 资溪县| 新余市| 江油市| 贺州市| 祁连县| 武川县| 榆社县| 广丰县| 鞍山市| 霍邱县| 临安市| 封丘县| 十堰市| 鸡东县|