[c3p0] 第二篇:使用c3p0,

來源:互聯網
上載者:User

[c3p0] 第二篇:使用c3p0,
前言

譯文是根據c3p0-0.9.5.1版本的官方文檔,加上自己的理解,整理翻譯而成。能力有限,譯文內容如果有誤或是理解有偏差,還請大家糾正!


使用c3p0

從使用者的角度看,c3p0隻是簡單的為使用者提供符合jdbc標準的DataSource對象。當建立這些DataSource對象的時候,使用者可以控制與其相關的各種屬性。一旦DataSource建立完成,DataSource背後的東西對使用者來講,就是完全透明的。


三種方式擷取c3p0帶串連池的DataSource

1、直接執行個體化並配置一個CombopooledDataSource bean;

2、使用DataSource工廠類;

3、通過直接執行個體化PoolBackedDataSource並設定它的ConnectionPoolDataSource來建立的帶有串連池的DataSource。


大部分使用者會發現執行個體化CombopooledDataSource一般來講是最方便的途徑。一旦執行個體化,c3p0的DataSource幾乎就可以綁定到任何JNDI相容的命名服務。


使用者建立DataSource的時候,如果沒有特別指定其各種屬性,c3p0會提供預設的屬性值,是通過硬式編碼方式實現的。但是,使用者也是可以通過設定檔等方式重寫這些屬性值的,如果是以設定檔的方式重寫,那麼設定檔需要放在CLASSPATH下或是ClassLoader可以找到的地方。


c3p0資料來源可以通過多種方式配置

1、命名為c3p0.properties的java.util.Properties屬性檔案。

2、更為先進的HOCON設定檔(例如:application.conf,application.json)。
3、命名為c3p0-config.xml的XML檔案。


執行個體化並配置ComboPooledDataSource

最簡單最直接的建立c3p0帶有串連池的DataSource就是執行個體化com.mchange.v2.c3p0.ComboPooledDataSource.這是一個JavaBean風格的類,有一個public的無慘構造器,但是在使用DataSource之前,你必須確保至少設定一個jdbcUrl屬性。你還可以設定user和password,如果你使用舊的不能預先載入的JDBC驅動,你還應該設定driverClass。

ComboPooledDataSource cpds = new ComboPooledDataSource();cpds.setDriverClass("org.postgresql.Driver");// loads the drivercpds.setJdbcUrl("jdbc:postgresql://localhost/testdb");cpds.setUser("swaldman");cpds.setPassword("test-password");// The settings below are potional -- c3p0 can work with defaultscpds.setMinPoolSize(5);cpds.setAcquireIncrement(5);cpds.setMaxPoolSize(20);// The DataSource cpds is now a fully configured and usable pooled DataSource


c3p0資料來源的屬性值可以由你來配置,或者直接使用預設的。c3p0支援命名配置,所以你可以同時配置多個DataSource。如果你想使用命名配置,那麼就要使用“配置名稱”作為構造參數來構造com.mchange.v2.c3p0.ComboPooledDataSource

ComboPooledDataSource cpds = new ComboPooledDataSource("intergalactoApp");...


當然,你也可以重寫它的任何配置屬性,和上面一樣。


使用資料來源工廠類

作為可供選擇的一種方案,你可以使用靜態工廠類com.mchange.v2.c3p0.DataSource以傳統的JDBC驅動的方式去建立不帶串連池的DataSource,然後從不帶串連池的資料來源建立帶串連池的資料來源。

DataSource ds_unpooled = DataSources.unpooledDataSource("jdbc:postgresql://localhost/testdb", "swaldman", "test-password");DataSource ds_pooled = DataSources.pooledDataSource(ds_unpooled);// The DataSource ds_pooled is now a fully configured and usable pooled DataSource.// The DataSource is using a default pool configuration and Postgres' JDBC driver// is presumed to have already been loaded via the jdbc.drivers system property or an// explicit call to Class.forName("org.postgresql.Driver") elsewhere....

如果你使用DataSources工廠類,又想以編程的方式重寫預設配置參數,你可以提供一個map集合屬性

DataSource ds_unpooled = DataSources.unpooledDataSource("jdbc:postgresql://localhost/testdb", "swaldman", "test-password");Map overrides = new HashMap();overrides.put("maxStatements", "200");// Stringified property values workoverrides.put("maxPoolSize", new Integer(50));// "boxed primitives" also work// create the PooledDataSource using the default configuration and our overridesDataSource ds_pooled = DataSources.pooledDataSource(ds_unpooled, overrides);// The DataSource ds_pooled is now a fully configured and usable pooled DataSource,// with Statement caching enabled for a maximum of up to 200 statements and a maximum of 50 Connection....

如果你使用命名配置,你可以直接指定資料來源的預設配置

// Create the PooledDataSource using the a named configuration and specified overrides "intergalactoApp" is a named configurationds_pooled = DataSources.pooledDataSource(ds_unpooled, "intergalactoApp", overrides);

查詢PooledDataSource的目前狀態

c3p0 DataSource 支援池,包含ComboPooledDataSource實現並通過DataSources.pooledDataSource(...)返回對象,所有com.mchange.v2.c3p0.PooledDataSource的介面實現,都可以利用多種方法查詢DataSource串連池的狀態。下面是查詢DataSource的簡單代碼:

// Fetch a JNDI-bound DataSourceInitialContext ictx = new InitialContext();DataSource ds = (DataSource) ictx.lookup("java:comp/env/jdbc/myDataSource");// make sure it's a c3p0 PooledDataSourceif (ds instanceof PooledDataSource) {PooledDataSource pds = (PooledDataSource) ds;System.err.println("num_connections: " + pds.getNumConnectionsDefaultUser());System.err.println("num_busy_connections: " + pds.getNumBusyConnectionsDefaultUser());System.err.println("num_idle_connections: " + pds.getNumIdleConnectionsDefaultUser());System.err.println();} else {System.err.println("Not a c3p0 PooledDataSource!");}

狀態查詢方法都類似於以下三個重載形式:

public int getNumConnectionsDefaultUser();public int getNumCOnnections(String username, String password);public int getNumConnectionsAllUsers();

c3p0以不同的驗證資訊維護各自的串連池。有眾多的方法讓你查詢單獨某個池的狀態,或者是匯總所有的資料。值得注意的是像maxPoolSize這樣的池配置參數是在每個認證上都會使用的。例如,如果你已經設定了maxPoolSize=20,DataSource正在管理著兩對username-password,預設的一個,另一個通過調用getConnection(user,password)建立,調用getNumConnectionsAllUsers(),最大能看到的串連數應該是40.


多數應用只需要從DataSource擷取預設的認證串連,典型的通過getXXXDefaultUser()收集串連資料。


還有串連池的真實資料,你可以取到每個DataSource的線程池狀態資料。請參考PooledDataSource可選操作的完整列表。


使用C3P0Registry引用DataSource

如果通過JNDI或者是其它方式不方便或是不太可能得到DataSource的引用,你可以使用C3P0Registry類找到有效c3p0 DataSource,它包含三個靜態方法:

public static Set getPooledDataSources();public static Set pooledDataSourcesByName(String dataSourceName);public static PooledDataSource pooledDataSourceByName(String dataSourceName);

第一個方法返回給你c3p0 PooledDataSources的Set集合。如果你確信你的應用只會產生一個PooledDataSources,或者你能通過配置參數區分DataSource(通過"getters"檢查),第一種方法就足夠了。


因為並不總是如此,c3p0 PooledDataSources有一個叫做dataSourceName的特殊屬性,當你構造DataSource的時候,你可以直接設定dataSourceName屬性,或者像其它屬性一樣對其進行配置。否則,dataSourceName將會預設兩種情況:

1、如果你用一個命名配置構造DataSource,就是你的配置名稱。

2、如果你使用預設的配置,就會有一個唯一的名字,但不可預測。


這裡並沒有保證dataSourceName是唯一的。例如,如果兩個c3p0 DataSource共用一個命名配置,而且你沒有編程式的設定dataSourceName,那麼這兩個資料來源將會共用配置名稱。可以使用pooledDataSourcesByName(...)得到特定dataSourceName的所有資料來源。


如果你確定DataSource的名字是唯一的(如果你想要使用C3P0Registry找到DataSource,你通常會願意這麼做),你可以使用更方便的方法pooledDataSourceByName(...),它將直接返回指定名字的DataSource的引用或者是null(如果沒有DataSource)。如果你在多個共用名稱的DataSource中使用pooledDataSourceByName(...),將會返回哪一個DataSource是沒有明確定義的。


c3p0 PooledDataSources使用之後的清理

c3p0建立DataSources之後,最簡單的清理方法是使用DataSources類定義的靜態銷毀方法。僅有PooledDataSources需要清理,如果在一個不帶串連池的DataSource或者是non-c3p0 DataSource中使用,DataSources.destroy(...)也是沒有危害的。

DataSource ds_pooled = null;try {DataSource ds_unpooled = DataSources.unpooledDataSource("jdbc:postgresql://localhost/testdb", "swaldman", "test-password");ds_pooled = DataSources.pooledDataSource(ds_unpooled);// Do all kinds of stuff with that sweet pooled DataSource...} finally {DataSources.destroy(ds_pooled);}

可供選擇的,c3p0的PooledDataSource介面包含一個close()方法,當你使用DataSource完成工作以後你可以調用它。所以,你可以轉換一個c3p0派生出的DataSource為PooledDataSource然後關閉它。

static void cleanup(DataSource ds) throws SQLException {// Make sure it's a c3p0 PooledDataSourceif (ds instanceof PooledDataSource) {PooledDataSource pds = (PooledDataSource) ds;pds.close();} elseSystem.err.println("Not a c3p0 PooledDataSource!");}

ComboPooledDataSource是PooledDataSource的執行個體,可以直接通過close()關閉。PooledDataSource實現了java.lang.AutoCloseable,所以他們可以被Java 7 + try-with-resources塊管理。


不是PooledDataSource的執行個體不能用close()方法,如果想要關閉他們優先在它們的finalize()中使用記憶體回收機制(garbage collection)。一如既往,析構(finalization)應該被認為是一個捕手,而不是一個提示或是清理資源的途徑。


進階:構建自己的PoolBackedDataSource

大部分程式員這麼做是有一些原因的,但是你可以一步步的構建PooledDataSource。通過執行個體化並配置一個無池DriverManagerDataSource,執行個體化一個WrapperConnectionPoolDataSource並設定一個無池DataSource作為它的nestedDataSource屬性,然後PoolBackedDataSource使用這些設定connectionPoolDataSource屬性。


如果你的驅動提供一個ConnectionPoolDataSource實現,這些事件序列就是首要的關鍵點,你會更傾向於這樣使用c3p0,而不是使用c3p0的WrapperConnectionPoolDataSource,你可以建立一個PoolBackedDataSource設定它的connectionPoolDataSource屬性。Statement池,ConnectionCustomizers,和很多c3p0特定的屬性不被第三方ConnectionPoolDataSource支援(第三方DataSource實現只能替代c3p0的DriverManagerDataSource沒有重大損失的功能)。


進階:原始串連和語句操作

注意:自c3p0-0.9.5起,通過代理c3p0支援標準JDBC4的unwrap()方法。注意如果你使用unwrap()方法,c3p0就不能清理任何你從原始Connections或是Statements產生的Statement或是ResultSet對象。使用者必須小心仔細的直接清理這些對象。此外,使用者應該注意不要以某種方式修改底層的Connections,致使它們不能再與其它的Connections替換,因為必須保持它們是適合於串連池的。


JDBC驅動有時候根據特定供應商,非標準API去定義Connection和Statement的實現。C3P0通過代理封裝這些對象,所以你不能轉換由C3P0返回的Connections或是Statements到特定供應商實現的類。C3P0並不提供任何方式去直接存取原始Connections和Statements,因為C3P0需要保持追蹤Statements和ResultSets的建立,防止資源流失和破壞串連池。


C3P0確實提供了一個API,允許你在底層Connection上反射調用非標準方法。為了使用它,第一步,轉換Connection為一個C3P0ProxyConnection。然後調用rawConnectionOperation(),應用java.lang.reflect.Method對象,你希望調用的非標準方法作為其參數。你提供的Method對象將會被你提供的第二個參數目標調用(靜態方法則為null),並且使用你提供的第三個參數。對於這個目標,任何的方法參數,你都可以應用特定的C3P0ProxyConnection.RAW_CONNECTION,在Method被調用之前,它將被底層特定供應商Connection對象替代。


C3P0ProxyStatement提供一個類似的API。
任何原始操作返回的Statements(包括Prepared和CallableStatements)和ResultSets都將被c3p0-managed,被父代理Connection的close()正確的清理。使用者必須仔細清理任何通過特定供應商返回的非標準資源。


這裡有一個例子,在Oracle-specific API上調用原始Connection的靜態方法:

C3P0ProxyConnection castCon = (C3P0ProxyConnection) c3p0DataSource.getConnection();Method m = CLOB.class.getMethod("createTemporary", new Class[] { Connection.class, boolean.class, int.class });Object[] args = new Object[] { C3P0ProxyConnection.RAW_CONNECTION, Boolean.valueOf(true), new Integer(10) };CLOB oracleCLOB = (CLOB) castCon.rawConnectionOperation(m, null, args);


C3P0包含了對一些Oracle-specific方法特殊的支援,請另行參考官方文檔。

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

相關關鍵詞:
相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.