c3p0连接测试的源码分析

来源:互联网 发布:mac迅雷提示信任 编辑:程序博客网 时间:2024/05/22 06:08

1.1  C3p0有三种方式检测连接的有效性

1:idleConnectionTestPeriod(异步)

 

每多少秒检查所有连接池中的空闲连接。Default: 0

 

C3P0PooledConnectionPool$PooledConnectionResourcePoolManager.refurbishIdleResource ()

 

public void refurbishIdleResource( Object resc ) throws Exception

                {

                    if (logger.isLoggable( MLevel.FINER ) )

                       finerLoggingTestPooledConnection( resc, "IDLE CHECK" );

                    else

                        //测试连接

                        testPooledConnection(resc );

                }

 

2:testConnectionOnCheckout(同步)

从池中取得可用的连接,同时检查有效性

 

C3P0PooledConnectionPool$PooledConnectionResourcePoolManager.refurbishResourceOnCheckout()

 

if ( testConnectionOnCheckout )

                    {

                        if (logger.isLoggable(MLevel.FINER ) )

                           finerLoggingTestPooledConnection( resc,"CHECKOUT" );

                        else

                           //测试连接

                           testPooledConnection( resc );

                    }

                    if ( connectionCustomizer !=null )

                    {

                        ConnectionphysicalConnection = null;

                        try

                        {

                            physicalConnection=  ((AbstractC3P0PooledConnection)resc).getPhysicalConnection();

                           connectionCustomizer.onCheckOut( physicalConnection,parentDataSourceIdentityToken );

                        }

                        catch(ClassCastException e)

                        {

                            throw SqlUtils.toSQLException("Cannot use a ConnectionCustomizer with a non-c3p0PooledConnection." +

                                            " PooledConnection: " + resc +

                                            "; ConnectionPoolDataSource: " + cpds.getClass().getName(), e);

                        }

                    }

3:testConnectionOnCheckin(异步)

释放连接到连接池,同时检查有效性

 

C3P0PooledConnectionPool$PooledConnectionResourcePoolManager.refurbishResourceOnCheckin ()

 

if ( connectionCustomizer !=null )

                    {

                        ConnectionphysicalConnection = null;

                        try

                        {

                            physicalConnection=  ((AbstractC3P0PooledConnection)resc).getPhysicalConnection();

                           connectionCustomizer.onCheckIn( physicalConnection,parentDataSourceIdentityToken );

                            SQLWarnings.logAndClearWarnings(physicalConnection );

                        }

                        catch(ClassCastException e)

                        {

                            throw SqlUtils.toSQLException("Cannot use a ConnectionCustomizer with a non-c3p0PooledConnection." +

                                            " PooledConnection: " + resc +

                                            "; ConnectionPoolDataSource: " + cpds.getClass().getName(), e);

                        }

                    }

                    else

                    {

                        PooledConnection pc =(PooledConnection) resc;

                        Connection con = null;

 

                        try

                        {

                            //we don't want anycallbacks while we're clearingwarnings

                           pc.removeConnectionEventListener( cl );

 

                            con =pc.getConnection();

                            SQLWarnings.logAndClearWarnings(con);

                        }

                        finally

                        {

                            // close theproxy Connection

                            ConnectionUtils.attemptClose(con);

                           

                           pc.addConnectionEventListener( cl );

                        }

                    }

                   

                    if ( testConnectionOnCheckin )

                    {

                        if (logger.isLoggable(MLevel.FINER ) )

                           finerLoggingTestPooledConnection( resc,"CHECKIN" );

                        else

                            //测试连接

                           testPooledConnection( resc );

                    }

 

 

总结:从代码上看,所有的方法的测试都是通过testPooledConnection方法实现的,只是采用不同的方式(同步或是异步),不同的场景(定时测试,获取连接,释放连接)调用之。

1.2   testPooledConnection

测试连接的方法

 

PooledConnection pc =(PooledConnection) resc;

 

                    Throwable[] throwableHolder= EMPTY_THROWABLE_HOLDER;

                    int status;

                    Connection conn = null;

                    Throwable rootCause = null;

                    try  

                    {

                        //we don't want anycallbacks while we're testingthe resource

                       pc.removeConnectionEventListener( cl );

 

                        conn =pc.getConnection(); //checkout proxyconnection

 

                        // if this is a c3p0 pooled-connection, let's getunderneath the

                        // proxy wrapper, and test the physical connectionsometimes.

                        // this is faster, when the testQuery would not otherwisebe cached,

                        // and it avoids a potential statusOnException()double-check by the

                        // PooledConnection implementation should the test queryprovoke an

                        // Exception

                        Connection testConn;

                        if (scache !=null) //when there is a statement cache...

                        {

                            // if it's the slow, default query, faster to test theraw Connection

                            if (testQuery ==null && connectionTesterIsDefault && c3p0PooledConnections)

                                testConn =((AbstractC3P0PooledConnection) pc).getPhysicalConnection();

                            else//test will likely be faster on the proxiedConnection, because the test query is probably cached

                                testConn =conn;

                        }

                        else//where there's no statement cache, better to use thephysical connection, if we can get it

                        {

                            if (c3p0PooledConnections)

                                testConn =((AbstractC3P0PooledConnection) pc).getPhysicalConnection();

                            else   

                                testConn =conn;

                        }

                     //具体的测试(测试类connectionTesterUnifiedConnectionTesterQueryConnectionTester)的实现类,测试sql: testQuery

                        if ( testQuery ==null )

                            status =connectionTester.activeCheckConnection( testConn );

                        else

                        {

                            if (connectionTesterinstanceofUnifiedConnectionTester)

                            {

                                throwableHolder= thp.getThrowableHolder();

                                status =((UnifiedConnectionTester) connectionTester).activeCheckConnection( testConn,testQuery, throwableHolder );

                            }

                            elseif (connectionTester instanceofQueryConnectionTester)

                                status =((QueryConnectionTester) connectionTester).activeCheckConnection( testConn,testQuery );

                            else

                            {

                                // System.err.println("[c3p0] WARNING: testQuery'" + testQuery +

                                // "' ignored. Please set a ConnectionTester thatimplements " +

                                //"com.mchange.v2.c3p0.advanced.QueryConnectionTester, or use the " +

                                // "DefaultConnectionTester, to test with the testQuery.");

 

                                logger.warning("[c3p0] testQuery '" + testQuery +

                                               "' ignored. Please set aConnectionTester that implements " +

                                               "com.mchange.v2.c3p0.QueryConnectionTester,or use the " +

                                "DefaultConnectionTester, to test with thetestQuery.");

                                status =connectionTester.activeCheckConnection( testConn );

                            }

                        }

                    }

                    catch (Exception e)

                    {

                        if (Debug.DEBUG)

                            logger.log(MLevel.FINE,"A Connection test failed with an Exception.", e);

                        //e.printStackTrace();

                        status =ConnectionTester.CONNECTION_IS_INVALID;

//                      System.err.println("rootCause------>");

//                      e.printStackTrace();

                        rootCause = e;

                    }

                    finally

                    {

                        if (rootCause ==null)

                            rootCause =throwableHolder[0];

                        elseif(throwableHolder[0] != null &&logger.isLoggable(MLevel.FINE))

                            logger.log(MLevel.FINE,"Internal Connection Test Exception", throwableHolder[0]);

                       

                        if (throwableHolder!=EMPTY_THROWABLE_HOLDER)

                            thp.returnThrowableHolder(throwableHolder );

                       

                        ConnectionUtils.attemptClose(conn );//invalidate proxy connection

                       pc.addConnectionEventListener( cl );  //should we move this to CONNECTION_IS_OKAY case? (itshould work either way)

                    }

 

                    switch (status)

                    {

                    case ConnectionTester.CONNECTION_IS_OKAY:

                        break;//no problem, babe

                    case ConnectionTester.DATABASE_IS_INVALID:

                        rp.resetPool();

                        //intentional cascade...

                    case ConnectionTester.CONNECTION_IS_INVALID:

                        Exception throwMe;

                        if (rootCause ==null)

                            throwMe = new SQLException("Connection is invalid");

                        else

                            throwMe = SqlUtils.toSQLException("Connection is invalid", rootCause);

                        throw throwMe;

                    default:

                        thrownew Error("Bad Connection Tester (" +

                                       connectionTester + ") " +

                                        "returned invalid status (" + status + ").");

                    }

 

 

 

 

   测试类:

Default:com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
<property name=" connectionTesterClassName "></property>

可以自定义,需要实现(UnifiedConnectionTester或者是

QueryConnectionTester)

 

测试sql

 

1.       automaticTestTable (优先级高)(测试时自动生成对应的查询语句)

2.       preferredTestQuery(默认为null,可以设置查询语句)

 

 

源码:C3P0PooledConnectionPoolManager

 private C3P0PooledConnectionPool createPooledConnectionPool(DbAuth auth)throws SQLException

    {

       String userName = auth.getUser();

        String automaticTestTable =getAutomaticTestTable( userName );

       String realTestQuery;

              //优先判断是否有automaticTestTable

       if (automaticTestTable != null)

       {

           //通过automaticTestTable生成testQuery;

           realTestQuery = initializeAutomaticTestTable( automaticTestTable, auth);

           if (this.getPreferredTestQuery( userName ) != null)

           {

                if ( logger.isLoggable(MLevel.WARNING ) )

                {

                    logger.logp(MLevel.WARNING,

                                   C3P0PooledConnectionPoolManager.class.getName(),

                                   "createPooledConnectionPool",

                                   "[c3p0] Both automaticTestTable and preferredTestQuery have beenset! " +

                                    "UsingautomaticTestTable, and ignoring preferredTestQuery. Real test query is''{0}''.",

                                   realTestQuery

                    );

                }

           }

       }

       Else//否则使用PreferredTestQuery

       {

 

           if (! defaultAuth.equals( auth ))

              ensureFirstConnectionAcquisition(auth );

 

           realTestQuery = this.getPreferredTestQuery( userName );

       }

 

       C3P0PooledConnectionPool out = new C3P0PooledConnectionPool( cpds,

                        auth,

                        this.getMinPoolSize(userName ),

                        this.getMaxPoolSize(userName ),

                        this.getInitialPoolSize( userName ),

                       this.getAcquireIncrement( userName ),

                       this.getAcquireRetryAttempts( userName ),

                       this.getAcquireRetryDelay( userName ),

                        this.getBreakAfterAcquireFailure(userName ),

                       this.getCheckoutTimeout( userName ),

                       this.getIdleConnectionTestPeriod( userName ),

                        this.getMaxIdleTime(userName ),

                        this.getMaxIdleTimeExcessConnections( userName),

                       this.getMaxConnectionAge( userName ),

                        this.getPropertyCycle(userName ),

                       this.getUnreturnedConnectionTimeout( userName ),

                       this.getDebugUnreturnedConnectionStackTraces(userName ),

                       this.getTestConnectionOnCheckout( userName ),

                       this.getTestConnectionOnCheckin( userName ),

                        this.getMaxStatements(userName ),

                       this.getMaxStatementsPerConnection( userName ),

                       this.getConnectionTester( userName ),

                       this.getConnectionCustomizer( userName ),

                        realTestQuery,

                        rpfact,

                        taskRunner,

                       parentDataSourceIdentityToken );

       return out;

}

 


0 0