Search code examples
springspring-boottomcat8hikaricp

HikariCP starts when "mvn spring-boot:run" but not with a deployable war file


We have a spring boot application.

When we do "mvn spring-boot:run", the application uses HikariCP. When we deploy a war file on tomcat, the CP is different and it crashes with connection closed after a few hours.

How can I force Hikari when deploying a war file?

This is our application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/xxx?
autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&connectionCollation=utf8_general_ci&characterSetResults=utf8&autoDeserialize=true&useConfigs=maxPerformance
spring.datasource.username=root
spring.datasource.password=___
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.open-in-view=true
spring.jpa.show-sql=false
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.DefaultNamingStrategy
spring.jpa.properties.javax.persistence.sharedCache.mode=ENABLE_SELECTIVE
spring.jpa.properties.hibernate.hikari.dataSource.cachePrepStmts=true
spring.jpa.properties.hibernate.hikari.dataSource.prepStmtCacheSize=250
spring.jpa.properties.hibernate.hikari.dataSource.prepStmtCacheSqlLimit=2048
spring.jpa.properties.hibernate.hikari.dataSource.useServerPrepStmts=true
spring.jpa.properties.hibernate.generate_statistics=false
spring.jpa.properties.hibernate.cache.use_structured_entries=true
spring.jpa.properties.hibernate.archive.autodetection=class
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_update=true
spring.jpa.properties.hibernate.connection.characterEncoding=utf-8
spring.jpa.properties.hibernate.connection.CharSet=utf-8
spring.jpa.properties.hibernate.connection.useUnicode=true
spring.jpa.properties.hibernate.connection.autocommit=true
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.region.factory_class=com.hazelcast.hibernate.HazelcastLocalCacheRegionFactory
spring.jpa.properties.hibernate.cache.region_prefix=
spring.jpa.properties.hibernate.cache.use_query_cache=true
spring.jpa.properties.hibernate.cache.use_minimal_puts=true
# JTA
spring.jta.enabled=true

This is the Application class:

package site.app;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.web.config.EnableSpringDataWebSupport;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * to make this deployable as war, this is necessary:
 * http://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html
 */
@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = "site")
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = { "site.repository" } )
@EntityScan(basePackages="site.model")
@EnableJpaAuditing
@EnableSpringDataWebSupport
@SpringBootApplication//mist: so that it can be run as war file
public class Application  extends SpringBootServletInitializer {

    /** mist: so that it can be run as war file */
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
//      System.out.println("Let's inspect the beans provided by Spring Boot:");
//
//      String[] beanNames = ctx.getBeanDefinitionNames();
//      Arrays.sort(beanNames);
//      for (String beanName : beanNames) {
//          System.out.println(beanName);
//      }

//       UserRepository repository = context.getBean(UserRepository.class);
//       //example data
//       User user = new User();
//       user.setEmail("nov34@test.com");
//       user.setFirstName("test");
//       user.setLastName("test");
//
//       repository.save(user);
//       Iterable<User> allUsers = repository.findAll();
//       for(User theUser : allUsers){
//           System.out.println(theUser.getEmail());
//       }
//       
//       SponsorRepository sponsorRepository = context.getBean(SponsorRepository.class);
//       
//       Sponsor sponsor = new Sponsor();
//       sponsor.setEmail("test@test.com");
//       sponsor.setSponsorPackage(SponsorPackage.DIAMOND);
//       
//       sponsorRepository.save(sponsor);

//      Page page = new Page();
//      page.setName("home");
//      PageRepository pageRepository = context.getBean(PageRepository.class);
//      pageRepository.save(page);

//      Link link = new Link();
//      link.setName("Registration");
//      link.setUrl("/");
//      LinkRepository linkRepository = context.getBean(LinkRepository.class);
//      linkRepository.save(link);
//       context.close();
    }


//    private DataSource dataSource() {
//        final HikariDataSource ds = new HikariDataSource();
//        ds.setMaximumPoolSize(100);
//        ds.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
//        ds.addDataSourceProperty("url", url);
//        ds.addDataSourceProperty("user", username);
//        ds.addDataSourceProperty("password", password);
//        ds.addDataSourceProperty("cachePrepStmts", true);
//        ds.addDataSourceProperty("prepStmtCacheSize", 250);
//        ds.addDataSourceProperty("prepStmtCacheSqlLimit", 2048);
//        ds.addDataSourceProperty("useServerPrepStmts", true);
//        return ds;
//    }


//    @Value("${spring.datasource.username}")
//    private String user;
//
//    @Value("${spring.datasource.password}")
//    private String password;
//
//    @Value("${spring.datasource.url}")
//    private String dataSourceUrl;
//
//    @Value("${spring.datasource.driverClassName}")
//    private String driverClassName;
//
////    @Value("${spring.datasource.connectionTestQuery}")
////    private String connectionTestQuery;
//
//    @Bean
//    public DataSource primaryDataSource() {
//        Properties dsProps = new Properties();
//        dsProps.setProperty("url", dataSourceUrl);
//        dsProps.setProperty("user", user);
//        dsProps.setProperty("password", password);
//
//        Properties configProps = new Properties();
////        configProps.setProperty("connectionTestQuery", connectionTestQuery);
//        configProps.setProperty("driverClassName", driverClassName);
//        configProps.setProperty("jdbcUrl", dataSourceUrl);
//
//        HikariConfig hc = new HikariConfig(configProps);
//        hc.setDataSourceProperties(dsProps);
////        hc.setMetricRegistry(metricRegistry);
//        return new HikariDataSource(hc);
//    }

}

This is the pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.bgjug</groupId>
    <artifactId>site</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name> web site</name>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
            <!--mist: exists in tomcat-->
            <!--<scope>provided</scope>-->
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--TODO mist: hikariCP stays here. I couldn't make it use it (I'm missing something). Now it uses either tomcat's pool or commons' pool-->
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <scope>compile</scope>
        </dependency>

        <!--  I need this to make entities auditable -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>

        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time-jsptags</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.jadira.usertype</groupId>
            <artifactId>usertype.core</artifactId>
            <version>${jadira.version}</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <!--mist: exists in tomcat-->
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

        <!--  spring security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
        </dependency>

        <!-- email -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

        <dependency>
            <groupId>com.hazelcast</groupId>
            <artifactId>hazelcast-hibernate4</artifactId>
            <version>${hazelcast.version}</version>
        </dependency>

        <!-- testing -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.186</version>
        </dependency>
    </dependencies>

    <!--mist: a profile that has the spring-boot:run plugin and a couple of dependencies, so that-->
    <!--spring-boot:run will work with an embedded tomcat. This profile is activated by default so that-->
    <!--no extra conf is needed. when we deploy on the server, we deactivate the profile, because we don't-->
    <!--want these dependencies in the war.-->
    <profiles>
        <profile>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <id>run.as.spring-boot.run</id>

            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                    </plugin>
                </plugins>
            </build>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
                <dependency>
                    <groupId>org.apache.tomcat.embed</groupId>
                    <artifactId>tomcat-embed-jasper</artifactId>
                </dependency>
            </dependencies>
        </profile>
    </profiles>

    <properties>
        <start-class>site.app.Application</start-class>
        <spring.version>4.1.5.RELEASE</spring.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-data-jpa.version>1.5.0.M1</spring-data-jpa.version>
        <hibernate-entitymanager.version>4.3.0.Final</hibernate-entitymanager.version>
        <jadira.version>3.1.0.CR10</jadira.version>
        <hazelcast.version>3.4</hazelcast.version>
        <rest-assured.version>2.4.0</rest-assured.version>
        <h2-database.version>1.3.156</h2-database.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Solution

  • So I've been told in the comments, that it's not going to work implicitly, because Tomcat's db pool somehow takes precedence, which is weird for me.

    One can configure it explicitly like this:

    @Configuration
    @ConfigurationProperties//: so that the conf properties are supplied here
    @SpringBootApplication//: so that it can be run as war file
    ...
    public class Application  extends SpringBootServletInitializer {
        @Value("${spring.datasource.username}")
        private String user;
    
        @Value("${spring.datasource.password}")
        private String password;
    
        @Value("${spring.datasource.url}")
        private String dataSourceUrl;
    
        @Value("${spring.datasource.driver-class-name}")
        private String driverClassName;
    
        @Bean
        public DataSource primaryDataSource() {
            Properties dsProps = new Properties();
            dsProps.setProperty("url", dataSourceUrl);
            dsProps.setProperty("user", user);
            dsProps.setProperty("password", password);
    
            Properties configProps = new Properties();
            configProps.setProperty("driverClassName", driverClassName);
            configProps.setProperty("jdbcUrl", dataSourceUrl);
    
            HikariConfig hc = new HikariConfig(configProps);
            hc.setDataSourceProperties(dsProps);
            return new HikariDataSource(hc);
        }
    }