适用版本:Spring Boot 3.x, HikariCP 5.x | 语言:Java 17+ | 数据库:MySQL 8.0
本示例演示如何在Spring Boot项目中集成和优化HikariCP连接池,包含完整的配置、使用、监控和最佳实践。
<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.0modelVersion>
<groupId>com.examplegroupId>
<artifactId>hikaricp-demoartifactId>
<version>1.0.0version>
<packaging>jarpackaging>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>3.2.0version>
<relativePath/>
parent>
<properties>
<java.version>17java.version>
<hikaricp.version>5.1.0hikaricp.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>com.zaxxergroupId>
<artifactId>HikariCPartifactId>
<version>${hikaricp.version}version>
dependency>
<dependency>
<groupId>com.mysqlgroupId>
<artifactId>mysql-connector-jartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>io.micrometergroupId>
<artifactId>micrometer-registry-prometheusartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.example'
version = '1.0.0'
java.sourceCompatibility = JavaVersion.VERSION_17
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'com.zaxxer:HikariCP:5.1.0'
implementation 'io.micrometer:micrometer-registry-prometheus'
runtimeOnly 'com.mysql:mysql-connector-j'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
# application.yml
spring:
application:
name: hikaricp-demo
# 数据源配置
datasource:
url: jdbc:mysql://localhost:3306/demo_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
# HikariCP 核心配置
hikari:
# 连接池名称
pool-name: DemoHikariPool
# 核心连接数配置
minimum-idle: 10 # 最小空闲连接数
maximum-pool-size: 50 # 最大连接池大小
# 超时配置
connection-timeout: 30000 # 连接超时时间 (30秒)
idle-timeout: 600000 # 空闲超时时间 (10分钟)
max-lifetime: 1800000 # 连接最大生命周期 (30分钟)
validation-timeout: 5000 # 连接验证超时时间 (5秒)
# 连接测试
connection-test-query: SELECT 1
# 性能优化
auto-commit: true # 自动提交
read-only: false # 读写模式
catalog: demo_db # 默认catalog
# 连接泄漏检测
leak-detection-threshold: 60000 # 泄漏检测阈值 (1分钟)
# 连接初始化
connection-init-sql: "SET NAMES utf8mb4"
# 数据源属性
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
useLocalSessionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false
# JPA 配置
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: true
# 日志配置
logging:
level:
com.zaxxer.hikari.HikariConfig: DEBUG
com.zaxxer.hikari.pool.HikariPool: INFO
com.zaxxer.hikari.pool.ProxyConnection: WARN
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
# Actuator 配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,hikaricp,loggers,prometheus
endpoint:
health:
show-details: always
metrics:
export:
prometheus:
enabled: true
# 服务端口
server:
port: 8080
# application-dev.yml (开发环境)
spring:
datasource:
hikari:
minimum-idle: 5
maximum-pool-size: 20
leak-detection-threshold: 30000
logging:
level:
com.zaxxer.hikari: DEBUG
---
# application-prod.yml (生产环境)
spring:
datasource:
hikari:
minimum-idle: 20
maximum-pool-size: 100
connection-timeout: 20000
leak-detection-threshold: 120000
logging:
level:
com.zaxxer.hikari.pool.HikariPool: INFO
com.zaxxer.hikari.pool.ProxyConnection: WARN
package com.example.hikaridemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* HikariCP Demo 应用启动类
* @author Demo Team
* @version 1.0.0
*/
@SpringBootApplication
@EnableScheduling
public class HikariDemoApplication {
public static void main(String[] args) {
SpringApplication.run(HikariDemoApplication.class, args);
System.out.println(" HikariCP Demo 应用启动成功!");
System.out.println(" 访问监控端点: http://localhost:8080/actuator/hikaricp");
System.out.println(" 访问健康检查: http://localhost:8080/actuator/health");
}
}
package com.example.hikaridemo.entity;
import jakarta.persistence.*;
import java.time.LocalDateTime;
/**
* 用户实体类
*/
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 50)
private String username;
@Column(nullable = false, length = 100)
private String email;
@Column(name = "full_name", length = 100)
private String fullName;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
// 构造函数
public User() {
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}
public User(String username, String email, String fullName) {
this();
this.username = username;
this.email = email;
this.fullName = fullName;
}
// Getter 和 Setter 方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getFullName() { return fullName; }
public void setFullName(String fullName) { this.fullName = fullName; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
@PreUpdate
public void preUpdate() {
this.updatedAt = LocalDateTime.now();
}
@Override
public String toString() {
return "User{id=" + id + ", username='" + username +
"', email='" + email + "', fullName='" + fullName + "'}";
}
}
package com.example.hikaridemo.repository;
import com.example.hikaridemo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* 用户数据访问接口
*/
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
/**
* 根据用户名查找用户
*/
Optional<User> findByUsername(String username);
/**
* 根据邮箱查找用户
*/
Optional<User> findByEmail(String email);
/**
* 模糊查询用户
*/
@Query("SELECT u FROM User u WHERE u.fullName LIKE %:name% OR u.username LIKE %:name%")
List<User> findUsersByNameContaining(@Param("name") String name);
/**
* 统计用户总数
*/
@Query("SELECT COUNT(u) FROM User u")
Long countTotalUsers();
}
package com.example.hikaridemo.service;
import com.example.hikaridemo.entity.User;
import com.example.hikaridemo.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
/**
* 用户业务服务类
*/
@Service
@Transactional
public class UserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
@Autowired
private UserRepository userRepository;
/**
* 创建用户
*/
public User createUser(String username, String email, String fullName) {
logger.info("创建新用户: username={}, email={}", username, email);
// 检查用户名是否已存在
if (userRepository.findByUsername(username).isPresent()) {
throw new RuntimeException("用户名已存在: " + username);
}
// 检查邮箱是否已存在
if (userRepository.findByEmail(email).isPresent()) {
throw new RuntimeException("邮箱已存在: " + email);
}
User user = new User(username, email, fullName);
User savedUser = userRepository.save(user);
logger.info("用户创建成功: {}", savedUser);
return savedUser;
}
/**
* 根据ID查找用户
*/
@Transactional(readOnly = true)
public Optional<User> findUserById(Long id) {
logger.debug("查找用户: id={}", id);
return userRepository.findById(id);
}
/**
* 根据用户名查找用户
*/
@Transactional(readOnly = true)
public Optional<User> findUserByUsername(String username) {
logger.debug("查找用户: username={}", username);
return userRepository.findByUsername(username);
}
/**
* 获取所有用户
*/
@Transactional(readOnly = true)
public List<User> getAllUsers() {
logger.debug("获取所有用户列表");
return userRepository.findAll();
}
/**
* 模糊搜索用户
*/
@Transactional(readOnly = true)
public List<User> searchUsers(String keyword) {
logger.debug("搜索用户: keyword={}", keyword);
return userRepository.findUsersByNameContaining(keyword);
}
/**
* 更新用户信息
*/
public User updateUser(Long id, String email, String fullName) {
logger.info("更新用户信息: id={}", id);
User user = userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("用户不存在: " + id));
if (email != null) {
user.setEmail(email);
}
if (fullName != null) {
user.setFullName(fullName);
}
User updatedUser = userRepository.save(user);
logger.info("用户信息更新成功: {}", updatedUser);
return updatedUser;
}
/**
* 删除用户
*/
public void deleteUser(Long id) {
logger.info("删除用户: id={}", id);
if (!userRepository.existsById(id)) {
throw new RuntimeException("用户不存在: " + id);
}
userRepository.deleteById(id);
logger.info("用户删除成功: id={}", id);
}
/**
* 获取用户总数
*/
@Transactional(readOnly = true)
public Long getTotalUserCount() {
return userRepository.countTotalUsers();
}
}
package com.example.hikaridemo.controller;
import com.example.hikaridemo.entity.User;
import com.example.hikaridemo.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* 用户管理 REST API 控制器
*/
@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "*")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
/**
* 创建用户
*/
@PostMapping
public ResponseEntity<?> createUser(@RequestBody Map<String, String> request) {
try {
String username = request.get("username");
String email = request.get("email");
String fullName = request.get("fullName");
if (username == null || email == null) {
return ResponseEntity.badRequest()
.body(Map.of("error", "用户名和邮箱不能为空"));
}
User user = userService.createUser(username, email, fullName);
return ResponseEntity.status(HttpStatus.CREATED).body(user);
} catch (Exception e) {
logger.error("创建用户失败", e);
return ResponseEntity.badRequest()
.body(Map.of("error", e.getMessage()));
}
}
/**
* 获取用户列表
*/
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
try {
List<User> users = userService.getAllUsers();
return ResponseEntity.ok(users);
} catch (Exception e) {
logger.error("获取用户列表失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* 根据ID获取用户
*/
@GetMapping("/{id}")
public ResponseEntity<?> getUserById(@PathVariable Long id) {
try {
Optional<User> user = userService.findUserById(id);
if (user.isPresent()) {
return ResponseEntity.ok(user.get());
} else {
return ResponseEntity.notFound().build();
}
} catch (Exception e) {
logger.error("获取用户失败: id={}", id, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Map.of("error", e.getMessage()));
}
}
/**
* 搜索用户
*/
@GetMapping("/search")
public ResponseEntity<List<User>> searchUsers(@RequestParam String keyword) {
try {
List<User> users = userService.searchUsers(keyword);
return ResponseEntity.ok(users);
} catch (Exception e) {
logger.error("搜索用户失败: keyword={}", keyword, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
/**
* 更新用户
*/
@PutMapping("/{id}")
public ResponseEntity<?> updateUser(@PathVariable Long id,
@RequestBody Map<String, String> request) {
try {
String email = request.get("email");
String fullName = request.get("fullName");
User user = userService.updateUser(id, email, fullName);
return ResponseEntity.ok(user);
} catch (Exception e) {
logger.error("更新用户失败: id={}", id, e);
return ResponseEntity.badRequest()
.body(Map.of("error", e.getMessage()));
}
}
/**
* 删除用户
*/
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteUser(@PathVariable Long id) {
try {
userService.deleteUser(id);
return ResponseEntity.ok(Map.of("message", "用户删除成功"));
} catch (Exception e) {
logger.error("删除用户失败: id={}", id, e);
return ResponseEntity.badRequest()
.body(Map.of("error", e.getMessage()));
}
}
/**
* 获取用户统计信息
*/
@GetMapping("/stats")
public ResponseEntity<Map<String, Object>> getUserStats() {
try {
Long totalUsers = userService.getTotalUserCount();
return ResponseEntity.ok(Map.of(
"totalUsers", totalUsers,
"timestamp", System.currentTimeMillis()
));
} catch (Exception e) {
logger.error("获取用户统计失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
package com.example.hikaridemo.monitoring;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.HikariPoolMXBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
/**
* HikariCP 连接池监控组件
*/
@Component
public class HikariPoolMonitor implements HealthIndicator {
private static final Logger logger = LoggerFactory.getLogger(HikariPoolMonitor.class);
@Autowired
private DataSource dataSource;
/**
* 健康检查
*/
@Override
public Health health() {
try {
if (dataSource instanceof HikariDataSource) {
HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
HikariPoolMXBean poolBean = hikariDataSource.getHikariPoolMXBean();
int totalConnections = poolBean.getTotalConnections();
int activeConnections = poolBean.getActiveConnections();
int idleConnections = poolBean.getIdleConnections();
int threadsAwaitingConnection = poolBean.getThreadsAwaitingConnection();
// 计算连接池使用率
double utilizationRate = totalConnections > 0 ?
(double) activeConnections / totalConnections : 0;
Health.Builder builder = Health.up()
.withDetail("poolName", hikariDataSource.getPoolName())
.withDetail("totalConnections", totalConnections)
.withDetail("activeConnections", activeConnections)
.withDetail("idleConnections", idleConnections)
.withDetail("threadsAwaitingConnection", threadsAwaitingConnection)
.withDetail("utilizationRate", String.format("%.2f%%", utilizationRate * 100));
// 根据使用率判断健康状态
if (utilizationRate > 0.9) {
builder.status("WARNING").withDetail("message", "连接池使用率过高");
} else if (threadsAwaitingConnection > 5) {
builder.status("WARNING").withDetail("message", "等待连接的线程过多");
}
return builder.build();
}
return Health.down().withDetail("error", "数据源不是HikariDataSource类型").build();
} catch (Exception e) {
logger.error("HikariCP健康检查失败", e);
return Health.down().withDetail("error", e.getMessage()).build();
}
}
/**
* 定时监控连接池状态
*/
@Scheduled(fixedRate = 30000) // 每30秒执行一次
public void monitorPoolStatus() {
if (dataSource instanceof HikariDataSource) {
HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
HikariPoolMXBean poolBean = hikariDataSource.getHikariPoolMXBean();
int totalConnections = poolBean.getTotalConnections();
int activeConnections = poolBean.getActiveConnections();
int idleConnections = poolBean.getIdleConnections();
int threadsAwaitingConnection = poolBean.getThreadsAwaitingConnection();
logger.info("HikariCP状态监控 - 总连接数:{}, 活跃连接:{}, 空闲连接:{}, 等待线程:{}",
totalConnections, activeConnections, idleConnections, threadsAwaitingConnection);
// 告警逻辑
double utilizationRate = totalConnections > 0 ?
(double) activeConnections / totalConnections : 0;
if (utilizationRate > 0.9) {
logger.warn("⚠️ 连接池使用率过高: {:.2f}%", utilizationRate * 100);
}
if (threadsAwaitingConnection > 5) {
logger.warn("⚠️ 等待连接的线程过多: {}", threadsAwaitingConnection);
}
}
}
}
package com.example.hikaridemo.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
/**
* HikariCP 数据源配置类
*/
@Configuration
public class HikariDataSourceConfig {
private static final Logger logger = LoggerFactory.getLogger(HikariDataSourceConfig.class);
@Value("${spring.datasource.url}")
private String jdbcUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
/**
* 创建 HikariCP 数据源
*/
@Bean
@Primary
public DataSource primaryDataSource() {
logger.info("正在初始化 HikariCP 数据源...");
HikariConfig config = new HikariConfig();
// 基础连接配置
config.setJdbcUrl(jdbcUrl);
config.setUsername(username);
config.setPassword(password);
config.setDriverClassName(driverClassName);
// 连接池配置
config.setPoolName("PrimaryHikariPool");
config.setMinimumIdle(10);
config.setMaximumPoolSize(50);
// 超时配置
config.setConnectionTimeout(30000);
config.setIdleTimeout(600000);
config.setMaxLifetime(1800000);
config.setValidationTimeout(5000);
// 连接测试
config.setConnectionTestQuery("SELECT 1");
// 性能优化配置
config.setAutoCommit(true);
config.setReadOnly(false);
config.setCatalog("demo_db");
// 泄漏检测
config.setLeakDetectionThreshold(60000);
// 数据源属性
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.addDataSourceProperty("useServerPrepStmts", "true");
config.addDataSourceProperty("rewriteBatchedStatements", "true");
HikariDataSource dataSource = new HikariDataSource(config);
logger.info("✅ HikariCP 数据源初始化完成");
logger.info(" 连接池配置 - 最小空闲:{}, 最大连接:{}",
config.getMinimumIdle(), config.getMaximumPoolSize());
return dataSource;
}
}
package com.example.hikaridemo;
import com.example.hikaridemo.entity.User;
import com.example.hikaridemo.repository.UserRepository;
import com.example.hikaridemo.service.UserService;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
import javax.sql.DataSource;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
/**
* HikariCP 集成测试
*/
@SpringBootTest
@ActiveProfiles("test")
@Transactional
class HikariDemoApplicationTests {
@Autowired
private DataSource dataSource;
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@Test
void testHikariDataSourceConfiguration() {
// 验证数据源类型
assertThat(dataSource).isInstanceOf(HikariDataSource.class);
HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
// 验证连接池配置
assertThat(hikariDataSource.getPoolName()).contains("HikariPool");
assertThat(hikariDataSource.getMaximumPoolSize()).isGreaterThan(0);
assertThat(hikariDataSource.getMinimumIdle()).isGreaterThanOrEqualTo(0);
System.out.println("✅ HikariCP 配置验证通过");
System.out.println(" 连接池名称: " + hikariDataSource.getPoolName());
System.out.println(" 最大连接数: " + hikariDataSource.getMaximumPoolSize());
System.out.println(" 最小空闲连接: " + hikariDataSource.getMinimumIdle());
}
@Test
void testDatabaseConnection() throws Exception {
// 测试数据库连接
try (var connection = dataSource.getConnection()) {
assertThat(connection).isNotNull();
assertThat(connection.isValid(5)).isTrue();
// 执行简单查询
try (var statement = connection.createStatement();
var resultSet = statement.executeQuery("SELECT 1 as test")) {
assertThat(resultSet.next()).isTrue();
assertThat(resultSet.getInt("test")).isEqualTo(1);
}
}
System.out.println("✅ 数据库连接测试通过");
}
@Test
void testUserCrudOperations() {
// 创建用户
User user = userService.createUser("testuser", "[email protected]", "Test User");
assertThat(user.getId()).isNotNull();
assertThat(user.getUsername()).isEqualTo("testuser");
// 查询用户
Optional<User> foundUser = userService.findUserById(user.getId());
assertThat(foundUser).isPresent();
assertThat(foundUser.get().getEmail()).isEqualTo("[email protected]");
// 更新用户
User updatedUser = userService.updateUser(user.getId(), "[email protected]", "Updated User");
assertThat(updatedUser.getEmail()).isEqualTo("[email protected]");
assertThat(updatedUser.getFullName()).isEqualTo("Updated User");
// 搜索用户
List<User> searchResults = userService.searchUsers("Updated");
assertThat(searchResults).isNotEmpty();
assertThat(searchResults.get(0).getFullName()).contains("Updated");
// 删除用户
userService.deleteUser(user.getId());
Optional<User> deletedUser = userService.findUserById(user.getId());
assertThat(deletedUser).isEmpty();
System.out.println("✅ 用户CRUD操作测试通过");
}
@Test
void testConnectionPoolPerformance() throws InterruptedException {
long startTime = System.currentTimeMillis();
// 并发获取连接测试
Thread[] threads = new Thread[20];
for (int i = 0; i < threads.length; i++) {
final int threadIndex = i;
threads[i] = new Thread(() -> {
try {
for (int j = 0; j < 10; j++) {
userService.createUser("user" + threadIndex + "_" + j,
"user" + threadIndex + "_" + j + "@example.com",
"User " + threadIndex + "_" + j);
}
} catch (Exception e) {
// 忽略重复键异常
}
});
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("✅ 连接池性能测试完成");
System.out.println(" 20个线程并发执行耗时: " + duration + "ms");
// 验证数据
Long totalUsers = userService.getTotalUserCount();
System.out.println(" 创建用户总数: " + totalUsers);
assertThat(duration).isLessThan(10000); // 应该在10秒内完成
}
}
-- 创建数据库
CREATE DATABASE demo_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 使用数据库
USE demo_db;
-- 用户表会由JPA自动创建,也可以手动创建
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
full_name VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
# 1. 克隆或创建项目
mkdir hikaricp-demo && cd hikaricp-demo
# 2. 构建项目
mvn clean compile
# 3. 启动应用
mvn spring-boot:run
# 或者使用Gradle
./gradlew bootRun
# 1. 创建用户
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"username":"john_doe","email":"[email protected]","fullName":"John Doe"}'
# 2. 获取所有用户
curl http://localhost:8080/api/users
# 3. 根据ID获取用户
curl http://localhost:8080/api/users/1
# 4. 搜索用户
curl "http://localhost:8080/api/users/search?keyword=john"
# 5. 更新用户
curl -X PUT http://localhost:8080/api/users/1 \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","fullName":"John Updated"}'
# 6. 获取用户统计
curl http://localhost:8080/api/users/stats
# 7. 查看连接池状态
curl http://localhost:8080/actuator/hikaricp
# 8. 查看健康检查
curl http://localhost:8080/actuator/health
# 9. 查看Prometheus指标
curl http://localhost:8080/actuator/prometheus
maximumPoolSize
恭喜! 您已经成功创建了一个完整的Spring Boot + HikariCP示例应用。这个示例包含了从基础配置到高级监控的所有功能,可以作为生产环境的参考模板。