本页将介绍Spring BootHikariCP的例子。

HikariCP是快速、简单、可靠且可用于生产的JDBC连接池。

Spring Boot 2.0版本中,默认的数据库连接池技术已经从Tomcat池切换到HikariCP

这是因为HikariCP提供了卓越的性能。

现在,自Spring Boot 2.0发布以来,spring-boot-starter-jdbcspring-boot-starter-data-jpa默认解决HikariCP的依赖关系,spring.datasource.type属性的默认值是HikariDataSource

Spring boot首先选择HikariCP,然后是Tomcat池,最后是Commons DBCP2(基于可用性)。

在这一页,我们将提供HikariCPSpring Boot数据和MySQL的完整例子。

我们将创建一个演示应用程序,其中我们将在数据库中执行创建和读取操作。

我们将在application.properties文件中配置HikariCP属性,例如connectionTimeoutminimumIdlemaxPoolSizeidleTimeoutmaxLifetimeautoCommit

示例工具版本

  1. Java 9
  2. Spring 5.0.7.RELEASE
  3. Spring Boot 2.0.3.RELEASE
  4. Maven 3.5.2
  5. MySQL 5.5
  6. Eclipse Oxygen

HikariCP 依赖

在使用HikariCP之前,我们需要确保我们已经解决了HikariCP的依赖。

如果我们使用的是Maven,我们可以使用以下依赖关系。

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.1.0</version>
</dependency> 

如果我们使用的是Spring Boot 2.0及以后的版本,我们不需要在pom.xmlbuild.gradle中加入HikariCP依赖,因为spring-boot-starter-jdbcspring-boot-starter-data-jpa默认会解决它。

这意味着,如果我们使用的依赖项是

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency> 

或者

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency> 

那么我们就不需要在pom.xmlbuild.gradle中包含HikariCP的依赖关系。

HikariCP 配置

对于Hikari连接池的配置,我们通过使用spring.datasource.type并在application.properties文件中指定连接池实现的完全限定名称来启用它,如下所示。

spring.datasource.type = com.zaxxer.hikari.HikariDataSource 

如果我们使用的是Spring Boot 2.0及以后的版本,Spring Boot会默认选择HikariDataSource,我们不需要配置上述行。

现在要配置Hikari特定的连接池设置,Spring Boot提供了spring.datasource.hikari.*前缀,可以在application.properties文件中使用。

我们将在这里讨论一些经常使用的配置。

1. connectionTimeout

connectionTimeout是客户端从连接池等待连接的最大毫秒数。我们需要对它进行如下配置。

spring.datasource.hikari.connection-timeout=20000 

2. minimumIdle

minimumIdleHikariCP在连接池中维护的最小空闲连接数。它被配置为如下。

spring.datasource.hikari.minimum-idle=5 

3. maximumPoolSize

maximumPoolSize配置最大连接池数大小。它的配置方法如下。

spring.datasource.hikari.maximum-pool-size=12 

4. idleTimeout

idleTimeout是允许一个连接在连接池中闲置的最大时间,以毫秒为单位。它的配置方法如下。

spring.datasource.hikari.idle-timeout=300000 

5. maxLifetime

maxLifetime是池中连接关闭后的最长生存时间(以毫秒为单位)。其配置如下所示。

spring.datasource.hikari.max-lifetime=1200000 

正在使用的连接将永远不会失效,只有当它关闭时,它才会在最长生存期后被删除。

6. autoCommit

autoCommit配置从池中返回的连接的默认自动提交行为。默认值为true

spring.datasource.hikari.auto-commit=true 

Spring Boot Data + HikariCP + MySQL 示例

我们将用Spring Boot DataHikariCPMySQL创建一个Spring Boot REST网络服务。

我们将使用CrudRepository来查询数据库。

我们还将使用RestTemplate创建一个REST客户端来测试我们的应用程序。

首先找到演示应用程序的项目结构。
在这里插入图片描述
找到我们例子中使用的MySQL表结构。

MySQL Table: articles

CREATE TABLE `articles` (
	`article_id` INT(5) NOT NULL AUTO_INCREMENT,
	`title` VARCHAR(200) NOT NULL,
	`category` VARCHAR(100) NOT NULL,
	PRIMARY KEY (`article_id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB; 

找到Maven文件以解决依赖性问题。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>com.concretepage</groupId>
	<artifactId>spring-boot-app</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>spring-boot-app</name>
	<description>Spring Boot Application</description>
	<parent>
	    <groupId>org.springframework.boot</groupId>
  	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>2.0.3.RELEASE</version>
 	    <relativePath/>
	</parent>
	<properties>
	    <java.version>9</java.version>
	</properties>
	<dependencies>
	  <dependency>
		 <groupId>org.springframework.boot</groupId>
		 <artifactId>spring-boot-starter-web</artifactId>
	  </dependency>
	  <dependency>
		 <groupId>org.springframework.boot</groupId>
		 <artifactId>spring-boot-starter-data-jpa</artifactId>
	  </dependency>
	  <dependency>
		 <groupId>mysql</groupId>
		 <artifactId>mysql-connector-java</artifactId>
		 <version>6.0.5</version>
	  </dependency>	  
	  <!-- Spring Boot Data 2.0 includes HikariCP by default -->
          <!-- dependency>
                 <groupId>com.zaxxer</groupId>
                 <artifactId>HikariCP</artifactId>
                 <version>3.1.0</version>
          </dependency -->	  	  	  
	  <dependency>
		 <groupId>javax.xml.bind</groupId>
		 <artifactId>jaxb-api</artifactId>
		 <version>2.3.0</version>
	  </dependency>  	
          <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-devtools</artifactId>
                 <optional>true</optional>
          </dependency> 
	</dependencies>
	<build>
	  <plugins>
		 <plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		 </plugin>
	  </plugins>
	</build>
</project> 

如果我们使用的Spring Boot版本低于Spring Boot 2.0,那么我们需要引入HikariCP的依赖,如下所示。

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.1.0</version>
</dependency> 

HikariCP 3.1.0适用于Java 8Java 9

现在找到属性文件来配置数据源和其他属性。

连接池将使用HikariCP进行配置。

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/concretepage
spring.datasource.username=root
spring.datasource.password=cp

#Spring Boot 2.0 includes HikariDataSource by default
#spring.datasource.type = com.zaxxer.hikari.HikariDataSource

spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=12
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.max-lifetime=1200000
spring.datasource.hikari.auto-commit=true

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.properties.hibernate.format_sql=true 

如果我们使用的Spring Boot版本低于Spring Boot 2.0,那么我们需要为HikariCP添加spring.datasource.type属性,如下所示。

spring.datasource.type = com.zaxxer.hikari.HikariDataSource 

现在找到演示程序中使用的其他文件。

ArticleRepository.java

package com.concretepage.repository;
import org.springframework.data.repository.CrudRepository;
import com.concretepage.entity.Article;

public interface ArticleRepository extends CrudRepository<Article, Long>  {
} 

Article.java

package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="articles")
public class Article implements Serializable { 
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="article_id")
        private long articleId;  
	@Column(name="title")
        private String title;
	@Column(name="category")	
	private String category;
	public long getArticleId() {
		return articleId;
	}
	public void setArticleId(long articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
} 

IArticleService.java

package com.concretepage.service;
import java.util.List;
import com.concretepage.entity.Article;

public interface IArticleService {
     List<Article> getAllArticles();
     void addArticle(Article article);
} 

ArticleService.java

package com.concretepage.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.concretepage.entity.Article;
import com.concretepage.repository.ArticleRepository;

@Service
public class ArticleService implements IArticleService {
	@Autowired
	private ArticleRepository articleRepository;

	@Override
	public List<Article> getAllArticles(){
		List<Article> list = new ArrayList<>();
		articleRepository.findAll().forEach(e -> list.add(e));
		return list;
	}
	@Override
	public void addArticle(Article article){
    	articleRepository.save(article);
	}
} 

ArticleInfo.java

package com.concretepage.controller;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;

public class ArticleInfo {
	@JsonInclude(Include.NON_NULL)
        private long articleId;
	@JsonInclude(Include.NON_NULL)
        private String title;
	@JsonInclude(Include.NON_NULL)
        private String category;
	public long getArticleId() {
		return articleId;
	}
	public void setArticleId(long articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	} 
} 

ArticleController.java

package com.concretepage.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import com.concretepage.entity.Article;
import com.concretepage.service.IArticleService;

@RestController
@RequestMapping("user")
public class ArticleController {
	@Autowired
	private IArticleService articleService;

	//Fetches all articles 
	@GetMapping(value= "articles")
	public ResponseEntity<List<ArticleInfo>> getAllArticles() {
		List<ArticleInfo> responseArticleList = new ArrayList<>();
		List<Article> articleList = articleService.getAllArticles();
		for (int i = 0; i < articleList.size(); i++) {
		    ArticleInfo ob = new ArticleInfo();
		    BeanUtils.copyProperties(articleList.get(i), ob);
		    responseArticleList.add(ob);    
		}
		return new ResponseEntity<List<ArticleInfo>>(responseArticleList, HttpStatus.OK);
	}
	
	//Creates a new article
	@PostMapping(value= "article")
	public ResponseEntity<Void> addArticle(@RequestBody ArticleInfo articleInfo, UriComponentsBuilder builder) {
		Article article = new Article();
		BeanUtils.copyProperties(articleInfo, article);
                articleService.addArticle(article);
                HttpHeaders headers = new HttpHeaders();
                headers.setLocation(builder.path("/article/{id}").buildAndExpand(article.getArticleId()).toUri());
                return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
	}
} 

现在找到Java类的Main方法来运行该应用程序。为了确保我们使用的是HikariCP,我们打印数据源名称。

SpringBootAppStarter.java

package com.concretepage;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootAppStarter implements CommandLineRunner {
    @Autowired
    DataSource dataSource;

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SpringBootAppStarter.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        System.out.println("DataSource = " + dataSource);
    }
} 

当我们启动我们的应用程序时,我们可以在服务器日志末尾的控制台看到以下信息。

输出

DataSource = HikariDataSource (HikariPool-1) 

现在找到REST客户端来测试该应用程序。

RestClientUtil.java


package com.concretepage.client;
import java.net.URI;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.concretepage.entity.Article;

public class RestClientUtil {
    public void getAllArticlesDemo() {
	HttpHeaders headers = new HttpHeaders();
	headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/articles";
        HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
        ResponseEntity<Article[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article[].class);
        Article[] articles = responseEntity.getBody();
        for(Article article : articles) {
              System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle()
                      +", Category: "+article.getCategory());
        }
    }
    public void addArticleDemo() {
    	HttpHeaders headers = new HttpHeaders();
    	headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/article";
	Article objArticle = new Article();
	objArticle.setTitle("Spring REST Security using Hibernate");
	objArticle.setCategory("Spring");
        HttpEntity<Article> requestEntity = new HttpEntity<Article>(objArticle, headers);
        URI uri = restTemplate.postForLocation(url, requestEntity);
        System.out.println(uri.getPath());    	
    }
    public static void main(String args[]) {
    	RestClientUtil util = new RestClientUtil();
    	util.addArticleDemo();
    	util.getAllArticlesDemo();    	
    }    
} 

当我们运行客户端时,我们将得到以下输出。

输出

Id:1, Title:Spring REST Security using Hibernate, Category: Spring 

测试应用程序

为了测试应用程序,首先按照文章中给出的方法在MySQL中创建表,并在application.properties文件中配置你的数据库凭证。然后,我们可以通过以下方式运行REST网络服务。

1. 使用 Maven 命令

下载项目的源代码。使用命令提示符进入项目的根文件夹并运行命令。

mvn spring-boot:run 

Tomcat服务器将被启动。

2. 使用 Eclipse

使用文章末尾的下载链接下载项目的源代码。将该项目导入eclipse。使用命令提示符,进入项目的根文件夹并运行。

mvn clean eclipse:eclipse 

然后在eclipse中刷新该项目。点击Run as -> Java Application来运行主类SpringBootAppStarterTomcat服务器将被启动。

3. 使用可执行 JAR

使用命令提示符,进入项目的根文件夹并运行该命令。

mvn clean package 

我们将在目标文件夹中得到可执行的JAR文件spring-boot-app-0.0.1-SNAPSHOT.jar。以下列方式运行这个JAR

java -jar target/spring-boot-app-0.0.1-SNAPSHOT.jar

Tomcat服务器将被启动。

现在我们已经准备好测试这个应用程序了。要运行Web服务客户端,在eclipse中进入RestClientUtil类,点击Run as -> Java Application

参考文献

【1】Spring Boot Reference Guide
【2】HikariCP
【3】Spring Boot 2.0 Release Notes
【4】Spring Boot + HikariCP

源码下载

spring-boot-hikaricp.zip

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐