1. 程式人生 > >JDBC從入門到放棄-07:JDBC的資料庫連線池

JDBC從入門到放棄-07:JDBC的資料庫連線池

JDBC從入門到放棄

07-JDBC的資料庫連線池

傳統資料庫連線

一般的資料庫連線操作

①獲取或建立資料庫連線。

②進行sql操作

③斷開資料庫連線。

這樣的搞發存在很多問題

  1. 耗費時間

普通的JDBC資料庫連線使用 DriverManager 來獲取,每次向資料庫建立連線的時候都要將 Connection 載入到記憶體中,再驗證使用者名稱和密碼(得花費0.05s~1s的時間)。

  1. 太頻繁連結資料庫,伺服器遭不住!

資料庫的連線資源並沒有得到很好的重複利用,用了馬上就斷開了.若同時有幾百人甚至幾千人線上,頻繁的進行資料庫連線操作將佔用很多的系統資源,嚴重的甚至會造成伺服器的崩潰。

  1. 太多資料庫連線不能被正常關閉,伺服器遭不住!

對於每一次資料庫連線,使用完後都必須得斷開。因為如果程式出現異常而未能關閉,將會導致資料庫系統中的記憶體洩漏,最終將導致重啟資料庫。總結:太多資料庫連線不能被正常關閉,伺服器遭不住!

  1. 資料庫被連線的數量失控,伺服器遭不住!

這種開發不能控制被建立的連線物件數,系統資源會被毫無顧及的分配出去,如連線過多,也可能導致記憶體洩漏,伺服器崩潰。

資料庫連線池

為解決傳統開發中的資料庫連線問題,可以採用資料庫連線池技術。

資料庫連線池的基本思想就是為資料庫連線建立一個“緩衝池”。預先在緩衝池中放入一定數量的連線,當需要建立資料庫連線時,只需從“緩衝池”中取出一個,使用完畢之後再放回去。資料庫連線池負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是重新建立一個。

連線池裡有些設定:最小資料庫連線數,最大資料庫連線數量,連線池通過這種機制,來控制資料庫連線的!

JDK為資料庫連線提供了一個介面:java.sql.DataSource,這個介面,和資料庫驅動中的Driver介面一樣,不用我們去實現,我們需要會用它的實現類就好了!它的實現類會有伺服器開發商(Tomcat)來提供實現,也有一些開源組織做了寫免費實現類:

  1. DBCP(Apache)
  2. C3P0
  3. DRUID(阿里巴巴)

所以DataSource雖然被稱為資料來源,但它卻是包含了連線池和連線池的管理兩個部分的功能,實質上我們稱為資料庫連線池!

資料庫連線池-DBCP的使用

引入相關依賴jar包

          <dependency>

               <groupId>org.apache.commons</groupId>

               <artifactId>commons-dbcp2</artifactId>

               <version>2.5.0</version>

          </dependency>

常規硬編碼

  1. 建立DBCP資料來源例項(BasicDataSource是DataSource介面的實現類)

BasicDataSource dataSource = new org.apache.commons.dbcp.BasicDataSource();

  1. 為DBCP資料來源例項設定連線資料庫必要的屬性

dataSource.setUsername("root");

     dataSource.setPassword("123456");

     dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/study");

dataSource.setDriverClassName("com.mysql.jdbc.Driver");

  1. 設定可選的資料來源屬性

a.資料庫連線池中初始化的連線數

dataSource.setInitialSize(10);

b.同一時刻可以向資料庫申請的最大的連線數

dataSource.setMaxTotal (50);

c.資料庫連線池中儲存的最少的空閒連線數

dataSource.setMinIdle(5);

d.等待資料連線池分配的最長時間,毫秒,超時丟擲異常

dataSource. setMaxWaitMillis (1000*5);

  1. 從資料來源中獲取資料庫連線

Connection conn = dataSource.getConnection();

測試程式碼

     /**

      * 測試dbcp資料庫連線池(硬編碼實現)

      */

     @SuppressWarnings("resource")

     @Test

     public void testDBCPHardCode() {

          try {

               BasicDataSource dataSource = new BasicDataSource();

               //設定必選的資料來源屬性

               dataSource.setUsername("root");

               dataSource.setPassword("123456");

               dataSource.setUrl("jdbc:mysql://localhost:3306/study");

               dataSource.setDriverClassName("com.mysql.jdbc.Driver");

               //設定可選的資料來源屬性

               dataSource.setInitialSize(10);//資料庫連線池中初始化的連線數

               dataSource.setMaxTotal(50);//同一時刻可以向資料庫申請的最大的連線數

               dataSource.setMinIdle(5);//.資料庫連線池中儲存的最少的空閒連線數

               dataSource.setMaxWaitMillis(1000*5);//

               //獲取資料來源連線

               Connection con = dataSource.getConnection();

               System.out.println(con);

          } catch (SQLException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }

     }

執行結果,正確

配置檔案

以上使用的是硬編碼的方式,將datasource的屬性值寫死在程式中,不利於後期維護和擴充套件。現在我們學習下,如何使用配置檔案的方式來進行DBCP連線池的建立和連線的獲取。

總體過程如下

Properties pop = new Properties();

InputStream in = DataSourceTest.class.getClassLoader().

getResourceAsStream("datasource.properties");

pop.load(in);

DataSource dataSource = BasicDataSourceFactory.createDataSource(pop);

Connection conn = dataSource.getConnection();

  • :建立配置檔案datasource.properties

注意:配置檔案的"鍵"是BasicDataSource類的setXxx()或getXxx()方法中的Xxx首寫字母變小寫的屬性:xxx

#必選的屬性

username=root

password=123456

url=jdbc:mysql://127.0.0.1:3306/study

driverClassNames=com.mysql.jdbc.Driver

#可選的屬性

initialSize=10

maxTotal=5

minIdle=5

maxWaitMillis=5000

  • 獲取屬性和連線池並測試

     /**

      * 測試dbcp資料庫連線池(配置檔案)

      */

     @Test

     public void testDBCPConfigFile() {

          try {

               //載入配置檔案

               Properties pop = new Properties();

               InputStream in = UseServiceTest.class.getClassLoader().

               getResourceAsStream("datasource.properties");

               pop.load(in);

               //設定配置檔案

               DataSource dataSource = BasicDataSourceFactory.createDataSource(pop);

               //獲取連線

               Connection con = dataSource.getConnection();

               System.out.println(con);

          }  catch (IOException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }catch (SQLException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          } catch (Exception e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }

     }

參考文獻

資料庫連線池-c3p0的使用

引入相關依賴jar包

          <dependency>

               <groupId>com.mchange</groupId>

               <artifactId>c3p0</artifactId>

               <version>0.9.5.2</version>

          </dependency>

常規硬編碼

/**

      * 測試c3p0資料庫連線池(硬編碼實現)

      */

     @Test

     public void testC3p0HardCode() {

          try {

               ComboPooledDataSource cpds = new ComboPooledDataSource();

               cpds.setDriverClass("com.mysql.jdbc.Driver");// loads the jdbc driver

               cpds.setJdbcUrl("jdbc:mysql://localhost:3306/study");

               cpds.setUser("root");

               cpds.setPassword("123456");

               cpds.setMaxStatements( 180 );

               // 獲取資料來源連線

               Connection con = cpds.getConnection();

               System.out.println(con);

          } catch (PropertyVetoException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }catch (SQLException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }

     }

關於其他配置引數以及含義,請查閱

這裡不再贅述。

測試結果如下,正確

配置檔案

這裡我們使用一下XML配置方式

<?xml version="1.0" encoding="UTF-8"?>

<c3p0-config>

     <named-config name="mysql">

          <property name="driverClass">com.mysql.jdbc.Driver</property>

          <property name="jdbcUrl">jdbc:mysql://localhost:3306/study</property>

          <property name="user">root</property>

          <property name="password">123456</property>

          <property name="acquireIncrement">50</property>

          <property name="initialPoolSize">100</property>

          <property name="minPoolSize">50</property>

          <property name="maxPoolSize">1000</property>

          <property name="maxStatements">0</property>

          <property name="maxStatementsPerConnection">5</property>

          <user-overrides user="master-of-the-universe">

               <property name="acquireIncrement">1</property>

               <property name="initialPoolSize">1</property>

               <property name="minPoolSize">1</property>

               <property name="maxPoolSize">5</property>

               <property name="maxStatementsPerConnection">50</property>

          </user-overrides>

     </named-config>

</c3p0-config>

  • 使用和編寫測試程式碼

     /**

      * 測試c3p0資料庫連線池(配置檔案)

      */

     @Test

     public void testC3p0ConfigFile() {

          try {

               // 載入配置檔案

               DataSource dataSource = new ComboPooledDataSource("mysql");

               // 獲取連線

               Connection con = dataSource.getConnection();

               System.out.println(con);

          }  catch (SQLException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          } catch (Exception e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

          }

     }

測試結果如下,可用。

參考文獻

至此我們的資料庫連線池的部分已經介紹完畢,關於DRUID的使用,有興趣的話可用自行研究一下,這裡就不贅述了。

現在學習資料庫連線池的使用,我們就也可以對我們的工具類中獲取資料庫連線部分做相應的改動了。具體操作很簡單,這裡也不再贅述。