1. 程式人生 > >c3p0配置之preferredTestQuery參數默認值探秘

c3p0配置之preferredTestQuery參數默認值探秘

默認值 param perf 而是 gets 源碼 .com deb util

http://www.mchange.com/projects/c3p0/

c3p0的配置參數preferredTestQuery用於檢測數據庫連接測試,檢測數據庫是否能連接成功。
Default: null
Defines the query that will be executed for all connection tests, if the default ConnectionTester (or some other implementation of QueryConnectionTester, or better yet FullQueryConnectionTester) is being used. Defining a preferredTestQuery that will execute quickly in your database may dramatically speed up Connection tests. (If no preferredTestQuery is set, the default ConnectionTester executes a getTables() call on the Connection‘s DatabaseMetaData. Depending on your database, this may execute more slowly than a "normal" database query.) NOTE: The table against which your preferredTestQuery will be run must exist in the database schema prior to your initialization of your DataSource. If your application defines its own schema, try automaticTestTable instead. [See "Configuring Connection Testing"]

與之對應的是參數:connectionTesterClassName,配置用於c3p0連接測試的實現類。
Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester
The fully qualified class-name of an implememtation of the ConnectionTester interface, or QueryConnectionTester if you would like instances to have access to a user-configured preferredTestQuery. This can be used to customize how c3p0 DataSources test Connections, but with the introduction of automaticTestTable and preferredTestQuery configuration parameters, "rolling your own" should be overkill for most users. [See "Configuring Connection Testing"]

connectionTesterClassName參數值必須實現接口:com.mchange.v2.c3p0.ConnectionTester,跟蹤源碼發現,其繼承關系如下:

    - com.mchange.v2.c3p0.ConnectionTester
        - com.mchange.v2.c3p0.QueryConnectionTester
            - com.mchange.v2.c3p0.FullQueryConnectionTester
                - com.mchange.v2.c3p0.UnifiedConnectionTester
                    - com.mchange.v2.c3p0.AbstractConnectionTester
                        - com.mchange.v2.c3p0.impl.DefaultConnectionTester


通常,我們都可能不會配置這2個參數,而是直接使用c3p0的默認配置。
那麽,它們的默認值分別是什麽呢?

com.mchange.v2.c3p0.impl.C3P0Defaults中定義了c3p0的默認參數配置,其中:

private final static ConnectionTester CONNECTION_TESTER = new DefaultConnectionTester();

顯然,當沒有明確定義參數connectionTesterClassName值時,c3p0默認使用的是com.mchange.v2.c3p0.impl.DefaultConnectionTester實現。
com.mchange.v2.c3p0.impl.DefaultConnectionTester定義如下方法:

public int activeCheckConnection(Connection c, String query, Throwable[] rootCauseOutParamHolder)
{
// if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX && logger.isLoggable( MLevel.FINER ) )
// logger.finer("Entering DefaultConnectionTester.activeCheckConnection(Connection c, String query). [query=" + query + "]");

    if (query == null)
        return activeCheckConnectionNoQuery( c, rootCauseOutParamHolder);
    else
    {
    .....
    }
}


當沒有明確定義preferredTestQuery值時,c3p0執行如下查詢:

private int activeCheckConnectionNoQuery(Connection c,  Throwable[] rootCauseOutParamHolder)
{
// if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX && logger.isLoggable( MLevel.FINER ) )
// logger.finer("Entering DefaultConnectionTester.activeCheckConnection(Connection c). [using default system-table query]");

    ResultSet rs = null;
    try
    {
        rs = c.getMetaData().getTables( null,
                        null,
                        "PROBABLYNOT",
                        new String[] {"TABLE"} );
        return CONNECTION_IS_OKAY;
    }
}

com.mysql.jdbc.DatabaseMetaData實現如下:

public java.sql.ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, final String[] types) throws SQLException {
    ...
    try {
        new IterateBlock<String>(getCatalogIterator(catalog)) {
            @Override
            void forEach(String catalogStr) throws SQLException {
                boolean operatingOnSystemDB = "information_schema".equalsIgnoreCase(catalogStr) || "mysql".equalsIgnoreCase(catalogStr)
                        || "performance_schema".equalsIgnoreCase(catalogStr);

                ResultSet results = null;
                try {
                    try {
              // 執行sql語句,檢測mysql是否可以連通 results
= stmt.executeQuery((!DatabaseMetaData.this.conn.versionMeetsMinimum(5, 0, 2) ? "SHOW TABLES FROM " : "SHOW FULL TABLES FROM ") + StringUtils.quoteIdentifier(catalogStr, DatabaseMetaData.this.quotedId, DatabaseMetaData.this.conn.getPedantic()) + " LIKE " + StringUtils.quoteIdentifier(tableNamePat, "‘", true)); } catch (SQLException sqlEx) { if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE.equals(sqlEx.getSQLState())) { throw sqlEx; } return; } ... } finally { if (results != null) { try { results.close(); } catch (Exception ex) { } results = null; } } } }.doForAll(); } finally { if (stmt != null) { stmt.close(); } } ... }

調試後發現,此時執行的sql語句為:SHOW FULL TABLES FROM `dbname` LIKE ‘PROBABLYNOT‘(dbname為實際數據庫名稱)即為preferredTestQuery參數的默認值。
執行該語句不返回任何記錄,但是可以通過該語句檢測mysql是否可以連通。

總結:
1. 通常不需要明確指定connectionTesterClassName參數,使用默認實現即可。
2. preferredTestQuery參數值最好明確配置,不要使用默認值。該參數通常配置為:"select 1" ,效率比"SHOW FULL TABLES FROM `dbname` LIKE ‘PROBABLYNOT‘‘高。

【參考】
http://josh-persistence.iteye.com/blog/2229929 深入淺出數據庫連接池c3p0
https://stackoverflow.com/questions/30521146/how-configure-connection-existence-check-in-c3p0 How configure connection existence check in C3P0?

c3p0配置之preferredTestQuery參數默認值探秘