SpringBoot與HikariCP整合,實現(xiàn)數(shù)據(jù)庫連接池動態(tài)優(yōu)化系統(tǒng)
作者:Java知識日歷
Craigslist 是全球最大的分類廣告網(wǎng)站,在其廣告發(fā)布和搜索系統(tǒng)中使用 HikariCP 來管理數(shù)據(jù)庫連接,支持大量的用戶訪問。
HikariCP 是目前最高效的 JDBC 連接池,能夠顯著提升應用程序的性能和響應速度。
我們?yōu)槭裁催x擇HikariCP?
- 低延遲:HikariCP 在基準測試中表現(xiàn)優(yōu)異,通常比其他流行的連接池(如 C3P0、DBCP)快得多。
- 優(yōu)化的鎖機制:通過減少不必要的同步操作和優(yōu)化鎖機制,HikariCP 提供了更快的連接獲取和釋放速度。
- 高效資源管理:HikariCP 使用較少的內(nèi)存來維護連接池,減少了垃圾回收的壓力。
- 最少的對象和線程:內(nèi)部使用少量的對象和線程,避免過多的上下文切換,從而提高整體性能。
- 簡單直觀:提供了簡單且直觀的配置選項,大多數(shù)情況下默認配置已經(jīng)足夠使用。
- 多種配置方式:支持屬性文件、Java 配置類等多種配置方式,靈活適應不同的需求。
- 兼容性強:可以與各種關系型數(shù)據(jù)庫一起使用,包括 MySQL、PostgreSQL、Oracle 等。
- 健康檢查:能夠自動檢測并移除死連接,確保連接池中的連接始終有效。
- 定期驗證:通過定期檢查和驗證連接的有效性來維護連接池的狀態(tài)。
- 靈活性:允許動態(tài)調(diào)整連接池的大小和其他參數(shù),滿足不同應用場景的需求。
- API支持:提供了豐富的 API 和回調(diào)機制,便于開發(fā)者進行定制化配置。
- 無縫集成:SpringBoot默認使用HikariCP作為其內(nèi)置的連接池實現(xiàn),無需額外配置即可使用。
哪些公司使用了HikariCP?
- Twitter在其推文發(fā)布和檢索系統(tǒng)中使用 HikariCP 來管理數(shù)據(jù)庫連接,支持大量的用戶互動。
- Uber在其調(diào)度系統(tǒng)和訂單管理系統(tǒng)中使用 HikariCP 來管理數(shù)據(jù)庫連接,確保實時性和可靠性。
- eBay在其電子商務平臺上使用 HikariCP 來管理數(shù)據(jù)庫連接,支持高并發(fā)的用戶請求。
- Salesforce在其銷售自動化和客戶服務系統(tǒng)中使用 HikariCP 來管理數(shù)據(jù)庫連接。
- Microsoft Azure在其各種云服務中使用 HikariCP 來管理數(shù)據(jù)庫連接,提供高效的數(shù)據(jù)處理能力。
- IBM在其內(nèi)部應用和云計算服務中使用 HikariCP 來管理數(shù)據(jù)庫連接。
- Spotify 是全球領先的音樂流媒體服務。用HikariCP優(yōu)化其后端服務的數(shù)據(jù)庫連接管理,支持高并發(fā)用戶請求。
- Square在其支付系統(tǒng)中使用HikariCP來管理數(shù)據(jù)庫連接,確保交易的高效處理。
- LinkedIn用于其龐大的用戶數(shù)據(jù)管理和推薦系統(tǒng)中的數(shù)據(jù)庫連接池。
- Airbnb在其復雜的后端系統(tǒng)中使用 HikariCP 來管理數(shù)據(jù)庫連接,確保用戶體驗的流暢性。
- Dropbox在其文件管理系統(tǒng)中使用 HikariCP 來管理數(shù)據(jù)庫連接,支持大量用戶的文件操作。
- Craigslist 是全球最大的分類廣告網(wǎng)站,在其廣告發(fā)布和搜索系統(tǒng)中使用 HikariCP 來管理數(shù)據(jù)庫連接,支持大量的用戶訪問。
代碼實操
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/><!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>dynamic-hikaricp-config</name>
<description>Demo project for Spring Boot with dynamic HikariCP configuration</description>
<properties>
<java.version>11</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>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/ecommerce
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
配置HikariCP數(shù)據(jù)源
package com.example.demo.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
// 創(chuàng)建HikariConfig實例
HikariConfig config = new HikariConfig();
// 設置JDBC URL
config.setJdbcUrl("jdbc:mysql://localhost:3306/ecommerce");
// 設置數(shù)據(jù)庫用戶名
config.setUsername("root");
// 設置數(shù)據(jù)庫密碼
config.setPassword("password");
// 啟用預編譯語句緩存
config.addDataSourceProperty("cachePrepStmts", "true");
// 設置預編譯語句緩存大小
config.addDataSourceProperty("prepStmtCacheSize", "250");
// 設置每個連接的最大預編譯語句數(shù)量
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
// 返回HikariDataSource實例
return new HikariDataSource(config);
}
}
處理與產(chǎn)品的REST請求
package com.example.demo.controller;
import com.example.demo.model.Product;
import com.example.demo.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
// 獲取所有產(chǎn)品
@GetMapping
public List<Product> getAllProducts() {
return productService.getAllProducts();
}
// 創(chuàng)建新產(chǎn)品
@PostMapping
public Product createProduct(@RequestBody Product product) {
return productService.createProduct(product);
}
// 根據(jù)ID獲取單個產(chǎn)品
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return productService.getProductById(id);
}
// 更新產(chǎn)品信息
@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody Product productDetails) {
return productService.updateProduct(id, productDetails);
}
// 刪除產(chǎn)品
@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
}
}
用于動態(tài)調(diào)整HikariCP配置
package com.example.demo.controller;
import com.example.demo.service.HikariConfigService;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/config")
public class HikariConfigController {
@Autowired
private HikariConfigService hikariConfigService;
// 獲取當前HikariCP配置
@GetMapping
public String getConfig() {
HikariDataSource dataSource = hikariConfigService.getDataSource();
return"Current configuration: maxPoolSize=" + dataSource.getMaximumPoolSize() +
", connectionTimeout=" + dataSource.getConnectionTimeout();
}
// 設置最大連接數(shù)
@PostMapping("/maxPoolSize/{size}")
public String setMaxPoolSize(@PathVariable int size) {
if (size > 0) {
hikariConfigService.setMaxPoolSize(size);
return"Updated maxPoolSize to " + size;
} else {
return"Invalid size";
}
}
// 設置連接超時時間
@PostMapping("/connectionTimeout/{timeout}")
public String setConnectionTimeout(@PathVariable long timeout) {
if (timeout >= 0) {
hikariConfigService.setConnectionTimeout(timeout);
return"Updated connectionTimeout to " + timeout + "ms";
} else {
return"Invalid timeout";
}
}
}
產(chǎn)品實體類
package com.example.demo.model;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Data
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // 產(chǎn)品ID
private String name; // 產(chǎn)品名稱
private double price; // 產(chǎn)品價格
private String description; // 產(chǎn)品描述
}
訂單實體類
package com.example.demo.model;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Data
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // 訂單ID
private Long productId; // 關聯(lián)的產(chǎn)品ID
private int quantity; // 訂單數(shù)量
private double totalAmount; // 總金額
}
Product Repository
package com.example.demo.repository;
import com.example.demo.model.Product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}
Order Repository
package com.example.demo.repository;
import com.example.demo.model.Order;
import org.springframework.data.jpa.repository.JpaRepository;
public interface OrderRepository extends JpaRepository<Order, Long> {
}
Product Service
package com.example.demo.service;
import com.example.demo.model.Product;
import com.example.demo.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
// 獲取所有產(chǎn)品
public List<Product> getAllProducts() {
return productRepository.findAll();
}
// 創(chuàng)建新產(chǎn)品
public Product createProduct(Product product) {
return productRepository.save(product);
}
// 根據(jù)ID獲取單個產(chǎn)品
public Product getProductById(Long id) {
return productRepository.findById(id).orElse(null);
}
// 更新產(chǎn)品信息
public Product updateProduct(Long id, Product productDetails) {
Product product = productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));
product.setName(productDetails.getName());
product.setPrice(productDetails.getPrice());
product.setDescription(productDetails.getDescription());
return productRepository.save(product);
}
// 刪除產(chǎn)品
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}
}
管理HikariCP配置的服務層
package com.example.demo.service;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class HikariConfigService {
@Autowired
private HikariDataSource dataSource;
// 獲取HikariDataSource實例
public HikariDataSource getDataSource() {
return dataSource;
}
// 設置最大連接數(shù)
public void setMaxPoolSize(int size) {
dataSource.setMaximumPoolSize(size);
}
// 設置連接超時時間
public void setConnectionTimeout(long timeout) {
dataSource.setConnectionTimeout(timeout);
}
}
Application
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
測試
設置最大連接數(shù)
curl -X POST http://localhost:8080/api/config/maxPoolSize/20
Respons:
Updated maxPoolSize to 20
設置連接超時時間
curl -X POST http://localhost:8080/api/config/connectionTimeout/30000
Respons:
Updated connectionTimeout to 30000ms
責任編輯:武曉燕
來源:
Java知識日歷