c3p0配置之preferredTestQuery参数默认值探秘

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?

时间: 2024-08-27 00:45:07

c3p0配置之preferredTestQuery参数默认值探秘的相关文章

SQL 自定义函数(Function)——参数默认值

sql server 自定义函数分为三种类型:标量函数(Scalar Function).内嵌表值函数(Inline Function).多声明表值函数(Multi-Statement Function) 标量函数:标量函数是对单一值操作,返回单一值. 内嵌表值函数:内嵌表值函数的功能相当于一个参数化的视图.它返回的是一个表,内联表值型函数没有由BEGIN-END 语句括起来的函数体. 多声明表值函数:它的返回值是一个表,但它和标量型函数一样有一个用BEGIN-END 语句括起来的函数体,返回值

Action 名称搜索顺序&amp;Action配置中的各项默认值

Action 名称的搜索顺序  一级一级往上,若命名空间包存在,但Action不存在,则跑到默认命名空间. Action 配置中的各项默认值    默认类class:ActionSupport    默认方法method:action的 execute    默认result name :success

C# 函数参数默认值

namespace 函数参数默认值 { class Program { public static void Test(int i =100) { Console.WriteLine("{0}",i); } static void Main(string[] args) { Test(); Test(222); Console.Read(); } } } 输出:100 222

java函数参数默认值

java通过函数的重载来实现函数参数默认值 public class ParameterDefault { /** * @param args */ public String getName(String givenName,String familyName){ return givenName+"."+familyName; } public String getName(String givenName){ return getName(givenName,"Xie&

【Struts2学习笔记(2)】Action配置中的各项默认值和Action中result的各种转发类型

一.Action配置中的各项默认值 <span style="font-size:18px;"><package name="itcast" namespace="/test" extends="struts-default"> <action name="helloworld" class="cn.itcast.action.HelloWorldAction&quo

ES6笔记之参数默认值(译)

原文链接:http://dmitrysoshnikov.com/ 原文作者:Dmitry Soshnikov 译者做了少量补充.这样的的文字是译者加的,可以选择忽略. 在这个简短的笔记中我们聊一聊ES6的又一特性:带默认值的函数参数.正如我们即将看到的,有些较为微妙的CASE. ES5及以下手动处理默认值 在ES6默认值特性出现前,手动处理默认值有几种方式: function log(message, level) { level = level || 'warning'; console.lo

ES6: 参数默认值及中间域

下午看了一章 ECMA-262 by Dmitry Soshnikov, 现在稍稍来小结下ES6中的参数默认值以及由此产生的参数中间作用域. 原文地址: http://dmitrysoshnikov.com/ecmascript/es6-notes-default-values-of-parameters/#conditional-intermediate-scope-for-parameters ES6中的参数默认值用法和其他语言都差不多,直接在参数后赋值: 1 function log(me

c++使用参数默认值实现默认构造函数

通常情况下的默认构造函数是不带任何的参数: class X{ private: int i; public: X() {} X( int ii):i(ii) {} }; 这其实等效于如下使用参数默认值的形式: class X{ private: int i; public: X( int ii=0):i(ii) {} //default constructor }; 若是将构造函数的实现不在类的声明中实现,可单独列出实现,但声明的时候是必须指定参数默认值: class X{ private: i

研究下JavaScript中的Rest参数和参数默认值

研究下JavaScript中的Rest参数和参数默认值 本文将讨论使 JavaScript 函数更有表现力的两个特性:Rest 参数和参数默认值. Rest 参数 通常,我们需要创建一个可变参数的函数,可变参数是指函数可以接受任意数量的参数.例如,String.prototype.concat 可以接受任何数量的字符串作为参数.使用 Rest 参数,ES6 为我们提供一种新的方式来创建可变参数的函数. 我们来实现一个示例函数 containsAll,用于检查一个字符串中是否包含某些子字符串.例如