HikariCP starts when “mvn spring-boot:run” but not with a deployable war file
我们有一个Spring Boot应用程序。
当我们执行" mvn spring-boot:run"时,该应用程序将使用HikariCP。
当我们在tomcat上部署war文件时,CP不??同,并且在几个小时后关闭连接后崩溃。
在部署战争文件时如何强制Hikari?
这是我们的application.properties:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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 |
这是应用程序类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 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("[email protected]"); // 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("[email protected]"); // 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | <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> site</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name> web site</name> <parent> <groupId>org.springframework.boot</groupId> spring-boot-starter-parent</artifactId> <version>1.2.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> <!--mist: exists in tomcat--> <!--<scope>provided</scope>--> </dependency> <dependency> <groupId>org.springframework</groupId> spring-aspects</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> spring-data-jpa</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> hibernate-entitymanager</artifactId> </dependency> <dependency> <groupId>mysql</groupId> 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> HikariCP</artifactId> <scope>compile</scope> </dependency> <!-- I need this to make entities auditable --> <dependency> <groupId>joda-time</groupId> joda-time</artifactId> </dependency> <dependency> <groupId>joda-time</groupId> joda-time-jsptags</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>org.jadira.usertype</groupId> usertype.core</artifactId> <version>${jadira.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> javax.servlet-api</artifactId> <!--mist: exists in tomcat--> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> jstl</artifactId> </dependency> <!-- spring security --> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> spring-security-taglibs</artifactId> </dependency> <!-- email --> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>com.hazelcast</groupId> hazelcast-hibernate4</artifactId> <version>${hazelcast.version}</version> </dependency> <!-- testing --> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> hamcrest-core</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.h2database</groupId> 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> true</activeByDefault> </activation> <id>run.as.spring-boot.run</id> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> 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> maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project> |
所以我在评论中被告知,它不会隐式工作,因为Tomcat的数据库池以某种方式优先,这对我来说很奇怪。
一个人可以像这样显式配置它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | @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); } } |
我也遇到了这个问题,最终这只是一个小问题。只有在确保tomcat-jdbc.jar或commons-dbcp.jar永远不会出现在您的类路径中的情况下,它绝对优先。您可以通过将这些依赖项(如果我通过传递方式下载)排除在外来确保这一点(这就是我所做的,只是找出pom中的哪些依赖关系在您的类路径中通过传递方式将它们下载)。完成此操作后,您的application.properties应该如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 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数据源。但是还有一点,它将使用驱动程序而不是推荐的dataSourceClassName。在这种情况下,必须在application.properties:
中具有spring.datasource.dataSourceClassName = com.mysql.jdbc.jdbc2.optional.MysqlDataSource之后使用Java Config。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | @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以进行隐式自动配置,并抛出异常:
1 | Caused by: java.lang.IllegalStateException: both driverClassName and dataSourceClassName are specified, one or the other should be used. |
由于spring boot从url属性推断出Driver,因此您无法同时为隐式自动配置设置Driver(推断)和dataSourceClassName。