1.普通的JDBC連接數據庫的弊端
普通的JDBC數據庫連接使用 DriverManager 來獲取,每次向數據庫建立連接的時候都要將 Connection 加載到內存中,再驗證用戶名和密碼(得花費0.05s~1s的時間)。需要數據庫連接的時候,就向數據庫要求一個,執行完成后再斷開連接。
這樣的方式將會消耗大量的資源和時間。數據庫的連接資源並沒有得到很好的重復利用.若同時有幾百人甚至幾千人在線,頻繁的進行數據庫連接操作將占用很多的系統資源,嚴重的甚至會造成服務器的崩潰。
對於每一次數據庫連接,使用完后都得斷開。否則,如果程序出現異常而未能關閉,將會導致數據庫系統中的內存泄漏,最終將導致重啟數據庫。這種開發不能控制被創建的連接對象數,系統資源會被毫無顧及的分配出去,如連接過多,也可能導致內存泄漏,服務器崩潰.
2.使用連接池的優勢
數據庫連接池的基本思想就是為數據庫連接建立一個“緩沖池”。預先在緩沖池中放入一定數量的連接,當需要建立數據庫連接時,只需從“緩沖池”中取出一個,使用完畢之后再放回去。數據庫連接池負責分配、管理和釋放數據庫連接,它允許應用程序重復使用一個現有的數據庫連接,而不是重新建立一個。它的優勢有:
(1)資源重用:由於數據庫連接得以重用,避免了頻繁創建,釋放連接引起的大量性能開銷。在減少系統消耗的基礎上,另一方面也增加了系統運行環境的平穩性。
(2)更快的系統反應速度:數據庫連接池在初始化過程中,往往已經創建了若干數據庫連接置於連接池中備用。此時連接的初始化工作均已完成。對於業務請求處理而言,直接利用現有可用連接避免了數據庫連接初始化和釋放過程的時間開銷,從而減少了系統的響應時間
(3)新的資源分配手段對於多應用共享同一數據庫的系統而言,可在應用層通過數據庫連接池的配置實現某一應用最大可用數據庫連接數的限制避免某一應用獨占所有的數據庫資源.
(4)統一的連接管理,避免數據庫連接泄露在較為完善的數據庫連接池實現中,可根據預先的占用超時設定,強制回收被占用連接,從而避免了常規數據庫連接操作中可能出現的資源泄露。
3.C3p0連接池的運用
(1)下載C3p0 jar包 下載地址:https://sourceforge.net/projects/c3p0/files/latest/download?source=files 下載完后,將src文件夾內的2個jar文件拷貝到項目中,然后導入
(2)設置C3p0配置文件,在項目的src目錄下創建一個 c3p0-config.xml(必須這個文件名) 的文件,具體配置如下:
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <!--默認配置--> <default-config> <property name="initialPoolSize">10</property> <!--設置初始連接池的大小 --> <property name="maxIdleTime">30</property> <!--設置連接池的最大空閑時間,如果超過這個時間,某個數據庫連接還沒有被使用,則會斷開掉這個連接,如果為0,則永遠不會斷開連接 --> <property name="maxPoolSize">100</property> <!--設置連接池的最大值,如果獲得新連接時會使連接總數超過這個值則不會再獲取新連接,而是等待其他連接釋放 --> <property name="minPoolSize">10</property> <!--設置連接池的最小值 --> <property name="maxStatements">100</property> <!--設置連接池中的最大Statements數量 --> </default-config> <!--配置連接池oracle--> <named-config name="oracle"> <!--數據庫類型 --> <property name="driverClass">oracle.jdbc.driver.OracleDriver</property> <!--數據庫驅動包 --> <property name="jdbcUrl">jdbc:oracle:thin:@localhost:1521:orcl</property> <!--數據庫地址 --> <property name="user">用戶名</property> <!--oracle用戶 --> <property name="password">用戶密碼</property> <!--用戶密碼 --> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <!--和默認設置一樣,也可以自定義設置 --> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">100</property> </named-config> <!--配置連接池mysql--> <named-config name="mysql"> <!--mysql數據庫 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <!--mysql驅動包 --> <property name="jdbcUrl">jdbc:mysql://localhost:3306/數據庫名</property> <!--數據庫地址 --> <property name="user">root</property> <!--用戶名 --> <property name="password">123456</property> <!--用戶密碼 --> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <!--和默認設置一樣,也可以自定義設置 --> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">100</property> </named-config> </c3p0-config>
(3)配置好 c3p0-config.xml 后,我們就編寫C3p0Utils工具類,用於獲取數據庫連接,具體代碼:
public class C3p0Utils { static ComboPooledDataSource cpds=null; static{ cpds = new ComboPooledDataSource("oracle"); //選擇連接池的配置,這里是oracle } /** * 獲得數據庫連接 */ public static Connection getConnection(){ try { return cpds.getConnection(); } catch (SQLException e) { e.printStackTrace(); return null; } } /** * 數據庫關閉操作 * 這里重寫close方法,調用close方法並不是真正的關閉連接,只是將連接放回連接池 */ public static void close(Connection conn,PreparedStatement pst,ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(pst!=null){ try { pst.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
(4)接下來我們去測試一下,工具類是否能使用,測試類代碼:
public class oracleTest { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; conn = C3p0Utils.getConnection();//調用工具類的getConnection()方法 String sql = "select * from emp";//SQL語句 User user = new User(); try { ps = conn.prepareStatement(sql); rs = ps.executeQuery(); while (rs.next()) { System.out.print(rs.getInt(1) + " "); System.out.print(rs.getInt(2) + " "); System.out.print(rs.getString(3) + " "); System.out.print(rs.getString(4) + " "); System.out.println(); } conn.close();//並不是真的關閉,只是將連接放回連接池 } catch (SQLException e) { e.printStackTrace(); } } }
運行的結果這里就不展示了,程序順利的查出了員工表(emp)的信息。簡單幾步就實現了的C3p0連接池的運用。其實實現C3p0的方式大致有三種,這種方式算是最好的了,其他兩種就不先不提了。當然,C3p0並不是那么的簡單,要想深入的了解C3p0連接池的原理,那可要花不少的時間哦。
歡迎大家來到知了堂社區學習——傳送門:http://www.zhiliaotang.com
最后填加一些 C3p0-config.xml 比較實用的配置及解釋:
<!--acquireIncrement:鏈接用完了自動增量3個。 --> <property name="acquireIncrement">3</property> <!--acquireRetryAttempts:鏈接失敗后重新試30次。--> <property name="acquireRetryAttempts">30</property> <!--acquireRetryDelay;兩次連接中間隔1000毫秒。 --> <property name="acquireRetryDelay">1000</property> <!--autoCommitOnClose:連接關閉時默認將所有未提交的操作回滾。 --> <property name="autoCommitOnClose">false</property> <!--breakAfterAcquireFailure:出錯時不把正在提交的數據拋棄。--> <property name="breakAfterAcquireFailure">false</property> <!--checkoutTimeout:100毫秒后如果sql數據沒有執行完將會報錯,如果設置成0,那么將會無限的等待。 --> <property name="checkoutTimeout">100</property> <!--connectionTesterClassName:通過實現ConnectionTester或QueryConnectionTester的類來測試連接。類名需制定全路徑。Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester--> <property name="connectionTesterClassName"></property> <!--factoryClassLocation:指定c3p0 libraries的路徑,如果(通常都是這樣)在本地即可獲得那么無需設置,默認null即可。--> <property name="factoryClassLocation">null</property> <!--idleConnectionTestPeriod:每60秒檢查所有連接池中的空閑連接。--> <property name="idleConnectionTestPeriod">60</property> <!--initialPoolSize:初始化時獲取三個連接,取值應在minPoolSize與maxPoolSize之間。 --> <property name="initialPoolSize">3</property> <!--maxIdleTime:最大空閑時間,60秒內未使用則連接被丟棄。若為0則永不丟棄。--> <property name="maxIdleTime">60</property> <!--maxPoolSize:連接池中保留的最大連接數。 --> <property name="maxPoolSize">15</property> <!--maxStatements:最大鏈接數。--> <property name="maxStatements">100</property> <!--maxStatementsPerConnection:定義了連接池內單個連接所擁有的最大緩存statements數。Default: 0 --> <property name="maxStatementsPerConnection"></property> <!--numHelperThreads:異步操作,提升性能通過多線程實現多個操作同時被執行。Default: 3--> <property name="numHelperThreads">3</property> <!--overrideDefaultUser:當用戶調用getConnection()時使root用戶成為去獲取連接的用戶。主要用於連接池連接非c3p0的數據源時。Default: null--> <property name="overrideDefaultUser">root</property> <!--overrideDefaultPassword:與overrideDefaultUser參數對應使用的一個參數。Default: null--> <property name="overrideDefaultPassword">password</property> <!--password:密碼。Default: null--> <property name="password"></property> <!--preferredTestQuery:定義所有連接測試都執行的測試語句。在使用連接測試的情況下這個一顯著提高測試速度。注意: 測試的表必須在初始數據源的時候就存在。Default: null--> <property name="preferredTestQuery">select id from test where id=1</property> <!--propertyCycle:用戶修改系統配置參數執行前最多等待300秒。Default: 300 --> <property name="propertyCycle">300</property> <!--testConnectionOnCheckout:因性能消耗大請只在需要的時候使用它。Default: false --> <property name="testConnectionOnCheckout">false</property> <!--testConnectionOnCheckin:如果設為true那么在取得連接的同時將校驗連接的有效性。Default: false --> <property name="testConnectionOnCheckin">true</property> <!--user:用戶名。Default: null--> <property name="user">root</property> <!--usesTraditionalReflectiveProxies:動態反射代理。Default: false--> <property name="usesTraditionalReflectiveProxies">false</property>