SpringBoot與HikariCP整合,實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池動(dòng)態(tài)優(yōu)化系統(tǒng)
作者:Java知識(shí)日歷
Craigslist 是全球最大的分類廣告網(wǎng)站,在其廣告發(fā)布和搜索系統(tǒng)中使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接,支持大量的用戶訪問(wèn)。
HikariCP 是目前最高效的 JDBC 連接池,能夠顯著提升應(yīng)用程序的性能和響應(yīng)速度。
我們?yōu)槭裁催x擇HikariCP?
- 低延遲:HikariCP 在基準(zhǔn)測(cè)試中表現(xiàn)優(yōu)異,通常比其他流行的連接池(如 C3P0、DBCP)快得多。
- 優(yōu)化的鎖機(jī)制:通過(guò)減少不必要的同步操作和優(yōu)化鎖機(jī)制,HikariCP 提供了更快的連接獲取和釋放速度。
- 高效資源管理:HikariCP 使用較少的內(nèi)存來(lái)維護(hù)連接池,減少了垃圾回收的壓力。
- 最少的對(duì)象和線程:內(nèi)部使用少量的對(duì)象和線程,避免過(guò)多的上下文切換,從而提高整體性能。
- 簡(jiǎn)單直觀:提供了簡(jiǎn)單且直觀的配置選項(xiàng),大多數(shù)情況下默認(rèn)配置已經(jīng)足夠使用。
- 多種配置方式:支持屬性文件、Java 配置類等多種配置方式,靈活適應(yīng)不同的需求。
- 兼容性強(qiáng):可以與各種關(guān)系型數(shù)據(jù)庫(kù)一起使用,包括 MySQL、PostgreSQL、Oracle 等。
- 健康檢查:能夠自動(dòng)檢測(cè)并移除死連接,確保連接池中的連接始終有效。
- 定期驗(yàn)證:通過(guò)定期檢查和驗(yàn)證連接的有效性來(lái)維護(hù)連接池的狀態(tài)。
- 靈活性:允許動(dòng)態(tài)調(diào)整連接池的大小和其他參數(shù),滿足不同應(yīng)用場(chǎng)景的需求。
- API支持:提供了豐富的 API 和回調(diào)機(jī)制,便于開(kāi)發(fā)者進(jìn)行定制化配置。
- 無(wú)縫集成:SpringBoot默認(rèn)使用HikariCP作為其內(nèi)置的連接池實(shí)現(xiàn),無(wú)需額外配置即可使用。
哪些公司使用了HikariCP?
- Twitter在其推文發(fā)布和檢索系統(tǒng)中使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接,支持大量的用戶互動(dòng)。
- Uber在其調(diào)度系統(tǒng)和訂單管理系統(tǒng)中使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接,確保實(shí)時(shí)性和可靠性。
- eBay在其電子商務(wù)平臺(tái)上使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接,支持高并發(fā)的用戶請(qǐng)求。
- Salesforce在其銷售自動(dòng)化和客戶服務(wù)系統(tǒng)中使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接。
- Microsoft Azure在其各種云服務(wù)中使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接,提供高效的數(shù)據(jù)處理能力。
- IBM在其內(nèi)部應(yīng)用和云計(jì)算服務(wù)中使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接。
- Spotify 是全球領(lǐng)先的音樂(lè)流媒體服務(wù)。用HikariCP優(yōu)化其后端服務(wù)的數(shù)據(jù)庫(kù)連接管理,支持高并發(fā)用戶請(qǐng)求。
- Square在其支付系統(tǒng)中使用HikariCP來(lái)管理數(shù)據(jù)庫(kù)連接,確保交易的高效處理。
- LinkedIn用于其龐大的用戶數(shù)據(jù)管理和推薦系統(tǒng)中的數(shù)據(jù)庫(kù)連接池。
- Airbnb在其復(fù)雜的后端系統(tǒng)中使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接,確保用戶體驗(yàn)的流暢性。
- Dropbox在其文件管理系統(tǒng)中使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接,支持大量用戶的文件操作。
- Craigslist 是全球最大的分類廣告網(wǎng)站,在其廣告發(fā)布和搜索系統(tǒng)中使用 HikariCP 來(lái)管理數(shù)據(jù)庫(kù)連接,支持大量的用戶訪問(wèn)。
代碼實(shí)操
<?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實(shí)例
HikariConfig config = new HikariConfig();
// 設(shè)置JDBC URL
config.setJdbcUrl("jdbc:mysql://localhost:3306/ecommerce");
// 設(shè)置數(shù)據(jù)庫(kù)用戶名
config.setUsername("root");
// 設(shè)置數(shù)據(jù)庫(kù)密碼
config.setPassword("password");
// 啟用預(yù)編譯語(yǔ)句緩存
config.addDataSourceProperty("cachePrepStmts", "true");
// 設(shè)置預(yù)編譯語(yǔ)句緩存大小
config.addDataSourceProperty("prepStmtCacheSize", "250");
// 設(shè)置每個(gè)連接的最大預(yù)編譯語(yǔ)句數(shù)量
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
// 返回HikariDataSource實(shí)例
return new HikariDataSource(config);
}
}
處理與產(chǎn)品的REST請(qǐng)求
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獲取單個(gè)產(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);
}
}
用于動(dòng)態(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;
// 獲取當(dāng)前HikariCP配置
@GetMapping
public String getConfig() {
HikariDataSource dataSource = hikariConfigService.getDataSource();
return"Current configuration: maxPoolSize=" + dataSource.getMaximumPoolSize() +
", connectionTimeout=" + dataSource.getConnectionTimeout();
}
// 設(shè)置最大連接數(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";
}
}
// 設(shè)置連接超時(shí)時(shí)間
@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)品實(shí)體類
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)品價(jià)格
private String description; // 產(chǎn)品描述
}
訂單實(shí)體類
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; // 關(guān)聯(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獲取單個(gè)產(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配置的服務(wù)層
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實(shí)例
public HikariDataSource getDataSource() {
return dataSource;
}
// 設(shè)置最大連接數(shù)
public void setMaxPoolSize(int size) {
dataSource.setMaximumPoolSize(size);
}
// 設(shè)置連接超時(shí)時(shí)間
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);
}
}
測(cè)試
設(shè)置最大連接數(shù)
curl -X POST http://localhost:8080/api/config/maxPoolSize/20
Respons:
Updated maxPoolSize to 20
設(shè)置連接超時(shí)時(shí)間
curl -X POST http://localhost:8080/api/config/connectionTimeout/30000
Respons:
Updated connectionTimeout to 30000ms
責(zé)任編輯:武曉燕
來(lái)源:
Java知識(shí)日歷