Search code examples
javaspringmybatisc3p0spring-mybatis

How can I initialize the c3p0 pool in advance?


I need to do a lot of real-time asynchronous query operations, and the expected effect is like the "second asynchronous query" range in the first log output.

But in fact, the first asynchronous query operation will always initialize "c3p0 pool", the effect is like "first asynchronous query" in the first log output.

The first query operation on the web page will have a noticeable pause because the "c3p0 pool" is only started now, and the subsequent queries will not be paused.

How can I do the initialization of "c3p0 pool" before the first query operation to avoid the pause in the first query operation?

log output:


Completed Tomcat initialization...
============================================

[2019-04-06 11:29:20,273] Artifact Gradle : humingk : humingk-1.0-SNAPSHOT.war (exploded): Artifact is deployed successfully
[2019-04-06 11:29:20,273] Artifact Gradle : humingk : humingk-1.0-SNAPSHOT.war (exploded): Deploy took 28,470 milliseconds
11:29:22.840 [http-nio-8080-exec-4] DEBUG org.apache.shiro.web.servlet.SimpleCookie - Found 'shiro-cookie' cookie value [7JUK8JeReLqOLB4SgQJ/5AOUuG***********************=]
11:29:22.900 [http-nio-8080-exec-4] DEBUG org.apache.shiro.mgt.DefaultSecurityManager - Found remembered PrincipalCollection.  Adding to the context to be used for subject construction by the SubjectFactory.

=============Start my first asynchronous query===============

====start initializing c3p0 pool=== (Seriously I don't want to delay it until now)

11:47:14.830 [http-nio-8080-exec-7] INFO  com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 3, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1bqz1r5a11us7ntzkwpkmf|1b23856e, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.cj.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1bqz1r5a11us7ntzkwpkmf|1b23856e, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/douban_movie?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&nullCatalogMeansCurrent=true, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 30, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 10, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
11:47:14.877 [http-nio-8080-exec-7] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier '/mchange-commons.properties' could not be found. Skipping.
11:47:14.877 [http-nio-8080-exec-7] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier '/mchange-log.properties' could not be found. Skipping.
11:47:14.877 [http-nio-8080-exec-7] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier '/c3p0.properties' could not be found. Skipping.
11:47:14.877 [http-nio-8080-exec-7] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier 'hocon:/reference,/application,/c3p0,/' could not be found. Skipping.
11:47:14.877 [http-nio-8080-exec-7] WARN  com.mchange.v2.resourcepool.BasicResourcePool - Bad pool size config, start 3 < min 10. Using 10 as start.
11:47:14.893 [http-nio-8080-exec-7] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - com.mchange.v2.resourcepool.BasicResourcePool@62ffa7a0 config: [start -> 10; min -> 10; max -> 30; inc -> 3; num_acq_attempts -> 3; acq_attempt_delay -> 1000; check_idle_resources_delay -> 0; max_resource_age -> 0; max_idle_time -> 0; excess_max_idle_time -> 0; destroy_unreturned_resc_time -> 0; expiration_enforcement_delay -> 0; break_on_acquisition_failure -> false; debug_store_checkout_exceptions -> false; force_synchronous_checkins -> false]
11:47:14.893 [http-nio-8080-exec-7] DEBUG com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager - Created new pool for auth, username (masked): 'ro******'.
11:47:14.893 [http-nio-8080-exec-7] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - acquire test -- pool size: 0; target_pool_size: 10; desired target? 1
11:47:14.893 [http-nio-8080-exec-7] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - awaitAvailable(): [unknown]

====finish initializing c3p0 pool=== 

11:47:15.564 [http-nio-8080-exec-7] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
11:47:15.595 [http-nio-8080-exec-7] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e5d3666]
11:47:15.638 [http-nio-8080-exec-7] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@526aab0d [wrapping: com.mysql.cj.jdbc.ConnectionImpl@47a7bea5]] will be managed by Spring
11:47:15.646 [http-nio-8080-exec-7] DEBUG org.humingk.movie.mapper.MovieMapper.selectMoviesByNameStart - ==>  Preparing: select movie.* from movie where movie.name like CONCAT('',?,'%') order by movie.rate desc limit 10 
11:47:15.717 [http-nio-8080-exec-7] DEBUG org.humingk.movie.mapper.MovieMapper.selectMoviesByNameStart - ==> Parameters: a(String)
11:47:15.798 [http-nio-8080-exec-7] DEBUG org.humingk.movie.mapper.MovieMapper.selectMoviesByNameStart - <==      Total: 10
11:47:15.814 [http-nio-8080-exec-7] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e5d3666]
11:47:15.814 [http-nio-8080-exec-7] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e5d3666]
11:47:15.814 [http-nio-8080-exec-7] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e5d3666]
11:47:15.814 [http-nio-8080-exec-7] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1e5d3666]

=================finish my first asynchronous query======================

=================Start my second asynchronous query===============

11:49:13.276 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
11:49:13.276 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@50729ffd]
11:49:13.276 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@250d6429 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@47a7bea5]] will be managed by Spring
11:49:13.276 [http-nio-8080-exec-1] DEBUG org.humingk.movie.mapper.MovieMapper.selectMoviesByNameStart - ==>  Preparing: select movie.* from movie where movie.name like CONCAT('',?,'%') order by movie.rate desc limit 10 
11:49:13.276 [http-nio-8080-exec-1] DEBUG org.humingk.movie.mapper.MovieMapper.selectMoviesByNameStart - ==> Parameters: w(String)
11:49:13.276 [http-nio-8080-exec-1] DEBUG org.humingk.movie.mapper.MovieMapper.selectMoviesByNameStart - <==      Total: 10
11:49:13.276 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@50729ffd]
11:49:13.276 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@50729ffd]
11:49:13.276 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@50729ffd]
11:49:13.276 [http-nio-8080-exec-1] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@50729ffd]

=================finish my second asynchronous query======================

more asynchronous query normally like second ...

my spring-mapper.xml :

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="driverClass" value="${jdbc.driverClassName}"/>
        <property name="maxPoolSize" value="30" />
        <property name="minPoolSize" value="10" />
        <property name="autoCommitOnClose" value="false" />
        <property name="checkoutTimeout" value="10000" />
        <property name="acquireRetryAttempts" value="3" />
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
        <property name="typeAliasesPackage" value="org.humingk.movie.entity" />
        <property name="mapperLocations" value="classpath:mapper/*Mapper.xml" />
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        <property name="basePackage" value="org.humingk.movie.mapper" />
    </bean>

Solution

  • Basically, what you need to do is call dataSource.getConnection().close() once your application has initialized.

    The old school way to do this for a web app would be to define a ServletContextListener. For a Spring app, you probably want an ApplicationListener for a ContextRefreshEvent. That might look something like...

    import com.mchange.v2.c3p0.ComboPooledDataSource
    
    @Component
    public DataSourceInitializer implements ApplicationListener<ContextRefreshedEvent> {
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
           ComboPooledDataSource dataSource = event.getApplicationContext().getBean("dataSource", ComboPooledDataSource.class);
           dataSource.getConnection().close();
        }
    }
    

    I'm just winging this, certainly haven't tried or compiled it, so apologies if that's not exactly right. But it should be close.

    See also ContextRefreshedEvent, ApplicationContext.