3

我们有一个弹簧启动应用程序。

当我们执行“mvn spring-boot:run”时,应用程序使用 HikariCP。当我们在 tomcat 上部署一个 war 文件时,CP 是不同的,它会在几个小时后崩溃并关闭连接。

部署war文件时如何强制Hikari?

这是我们的 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

这是应用程序类:

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);
//    }

}

这是 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>
4

2 回答 2

2

所以我在评论中被告知,它不会隐式工作,因为 Tomcat 的数据库池以某种方式优先,这对我来说很奇怪。

可以像这样显式配置它:

@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);
    }
}
于 2015-04-17T21:26:12.683 回答
1

我也遇到了这个问题,最后这只是一个小问题。只有在您确保 tomcat-jdbc.jar 或 commons-dbcp.jar 永远不会出现在您的类路径中时,它才绝对优先。如果它们被传递下载,您可以通过排除这些依赖项来确保这一点(这就是我所做的,只需找出 pom 中的哪些依赖项将这些传递下载到您的类路径中)。完成此操作后,您的 application.properties 应如下所示:

# hikariCP 
  spring.jpa.databasePlatform=org.hibernate.dialect.MySQLDialect
  spring.datasource.url=jdbc:mysql://localhost:3306/exampledb
  spring.datasource.username=root
  spring.datasource.password=
  spring.datasource.poolName=SpringBootHikariCP
  spring.datasource.maximumPoolSize=5
  spring.datasource.minimumIdle=3
  spring.datasource.maxLifetime=2000000
  spring.datasource.connectionTimeout=30000
  spring.datasource.idleTimeout=30000
  spring.datasource.pool-prepared-statements=true
  spring.datasource.max-open-prepared-statements=2500

它将隐式配置 HikariCP 数据源。但还有一件事,它将使用 Driver 而不是推荐的 dataSourceClassName。在这种情况下,您必须在 application.properties 中有 spring.datasource.dataSourceClassName=com.mysql.jdbc.jdbc2.optional.MysqlDataSource 之后使用 Java Config:

@Configuration
@ComponentScan
class DataSourceConfig {

  @Value("${spring.datasource.username}")
  private String user;

  @Value("${spring.datasource.password}")
  private String password;

  @Value("${spring.datasource.url}")
  private String dataSourceUrl;

  @Value("${spring.datasource.dataSourceClassName}")
  private String dataSourceClassName;

  @Value("${spring.datasource.poolName}")
  private String poolName;

  @Value("${spring.datasource.connectionTimeout}")
  private int connectionTimeout;

  @Value("${spring.datasource.maxLifetime}")
  private int maxLifetime;

  @Value("${spring.datasource.maximumPoolSize}")
  private int maximumPoolSize;

 @Value("${spring.datasource.minimumIdle}")
 private int minimumIdle;

 @Value("${spring.datasource.idleTimeout}")
 private int idleTimeout;

 @Bean
 public DataSource primaryDataSource() {
      Properties dsProps = new Properties();
      dsProps.put("url", dataSourceUrl);
      dsProps.put("user", user);
      dsProps.put("password", password);
      dsProps.put("prepStmtCacheSize",250);
      dsProps.put("prepStmtCacheSqlLimit",2048);
      dsProps.put("cachePrepStmts",Boolean.TRUE);
      dsProps.put("useServerPrepStmts",Boolean.TRUE);

      Properties configProps = new Properties();
         configProps.put("dataSourceClassName", dataSourceClassName);
         configProps.put("poolName",poolName);
         configProps.put("maximumPoolSize",maximumPoolSize);
         configProps.put("minimumIdle",minimumIdle);
         configProps.put("minimumIdle",minimumIdle);
         configProps.put("connectionTimeout", connectionTimeout);
         configProps.put("idleTimeout", idleTimeout);
         configProps.put("dataSourceProperties", dsProps);

     HikariConfig hc = new HikariConfig(configProps);
     HikariDataSource ds = new HikariDataSource(hc);
     return ds;
    }
  }

在 application.properties 中为隐式自动配置定义 dataSourceClassName 并抛出异常:

Caused by: java.lang.IllegalStateException: both driverClassName and dataSourceClassName are specified, one or the other should be used.

由于 spring boot 从 url 属性推断 Driver 并且您不能同时设置 Driver (inferred) 和 dataSourceClassName 以进行隐式自动配置。

于 2015-08-01T06:59:19.183 回答