概述
在这个教程中,我们将学习如何使用 FlexyPool 与 Spring Boot 和 H2 配合使用 HikariCP 进行数据库连接池管理。它是一个建立在主流连接池之上的强大工具。
什么是FlexyPool?
现代Web应用中的一个重要方面是连接池管理。它确保多个客户端共享数据库连接,从而实现更快、更高效的数据库访问。
然而,管理连接池是一项复杂且具有挑战性的任务。当客户端数量增加和应用复杂性提高时,这一点尤为明显。这时,FlexyPool 就派上用场了。
FlexyPool 是一个强大的连接池管理工具,它简化了数据库连接的管理并优化性能。简单来说,它作为 Hikari、C3P0、DBCP2、Tomcat 和 Vibur 等主要连接池的代理。为了达到目标,库提供了指标和故障转移策略,可以根据需要动态调整给定池的大小:
2.1. FlexyPool 属性
FlexyPool 提供了两个重要属性:
-
connectionAcquireTimeThresholdMillis
:定义连接获取请求的时间阈值。超过这个时间后,将发布ConnectionAcquireTimeThresholdExceededEvent
。 -
connectionLeaseTimeThresholdMillis
:这是连接可以租赁的最大时间,然后返回到池中。当池超过这个阈值时,会发布ConnectionLeaseTimeThresholdExceededEvent
。
2.2. FlexyPool 策略
FlexyPool 提供两种策略来应对连接池获取失败的情况。
第一个策略是 IncrementPoolOnTimeoutConnectionAcquiringStrategy
。在这种策略下,如果在连接获取过程中超时,FlexyPool 将增加目标连接池的最大大小。该策略有两个选项:maxOverflowPoolSize
和 timeoutMillis
。
maxOverflowPoolSize
设置目标连接池可以扩展到的最大限制。
timeoutMillis
设置在尝试池大小增加之前等待的时间,其默认值为连接池的超时值。
策略 RetryConnectionAcquiringStrategy
指令 FlexyPool 在尝试从池中获取连接并重试 retryAttempts
次后放弃。retryAttempts
表示尝试的重试次数。
我们将在 FlexyPoolDataSource
的配置中设置这些策略。
安装
首先,让我们安装 HikariCP 连接池:
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.1.0</version>
</dependency>
接下来,添加 FlexyPool 的依赖项,HikariCP 配置适配器 和 Micrometer 适配器:
<dependency>
<groupId>com.vladmihalcea.flexy-pool</groupId>
<artifactId>flexy-hikaricp</artifactId>
<version>2.2.3</version>
<exclusions>
<exclusion>
<groupId>com.vladmihalcea.flexy-pool</groupId>
<artifactId>flexy-dropwizard-metrics</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.vladmihalcea.flexy-pool</groupId>
<artifactId>flexy-micrometer-metrics</artifactId>
<version>2.2.3</version>
</dependency>
由于我们使用 Micrometer 作为度量实现,因此默认排除了 Dropwizard-Metrics。此外,FlexyPool 对其他支持的连接池框架也有 安装指南。如果你使用的 Java 版本低于 1.8,这也非常有用。
配置
要使 FlexyPool 起作用,我们首先需要一个 FlexyPoolDataSource
数据源。这需要针对所使用的连接池(如 HikariDataSource)的特定数据源。现在,让我们设置它们。
4.1. HikariDataSource
配置
首先,我们使用内存中的 H2 数据库配置 Hikari 数据源:
@Bean
public HikariDataSource hikariDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=runscript from 'classpath:/db.sql'");
config.setUsername("");
config.setPassword("");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.addDataSourceProperty("minimumPoolSize", "1");
config.addDataSourceProperty("maximumPoolSize", "3");
config.addDataSourceProperty("connectionTimeout", "1000");
return new HikariDataSource(config);
}
在这里,我们添加了 maximumPoolSize
和 connectionTimeout
属性。正如我们之前看到的,这些属性对 FlexyPool 的 IncrementPoolOnTimeoutConnectionAcquiringStrategy
有帮助。
接下来,我们通过 HikariDataSource
配置一个bean:
@Bean
public Configuration<HikariDataSource> flexypoolConfiguration() {
HikariDataSource dataSource = hikariDataSource();
return new Configuration.Builder<>(UUID.randomUUID().toString(), dataSource, HikariCPPoolAdapter.FACTORY)
.setMetricsFactory(MicrometerMetrics::new)
.setConnectionProxyFactory(ConnectionDecoratorFactoryResolver.INSTANCE.resolve())
.setMetricLogReporterMillis(TimeUnit.SECONDS.toMillis(5))
.setMetricNamingUniqueName(UniqueNamingStrategy.INSTANCE)
.setJmxEnabled(true)
.setJmxAutoStart(true)
.setConnectionAcquireTimeThresholdMillis(50L)
.setConnectionLeaseTimeThresholdMillis(250L)
.setEventListenerResolver(() -> Arrays.asList(
new ConnectionAcquireTimeoutEventListener(),
new ConnectionAcquireTimeThresholdExceededEventListener(),
new ConnectionLeaseTimeThresholdExceededEventListener()))
.build();
}
这个配置:
- 启用了 JMX 报告
- 设置度量实现为 Micrometer。Micrometer 适配器默认使用
SimpleMetricsRegistry
。但是,它可以自定义以使用集成监控报告工具,如 Ganglia 或 Graphite。 - 向各种连接事件添加监听器:
ConnectionAcquireTimeoutEvent
、ConnectionAcquireTimeThresholdExceededEvent
和ConnectionLeaseTimeThresholdExceeded
。值得注意的是,这些监听器是同步的,不应执行耗时任务。 - 设置连接租赁时间为 250ms
- 设置连接获取时间为 50ms
4.2. FlexyPoolDataSource
配置
现在,让我们配置一个 FlexyPoolDataSource
bean:
@Bean(initMethod = "start", destroyMethod = "stop")
public FlexyPoolDataSource<HikariDataSource> flexypoolDataSource() {
Configuration<HikariDataSource> configuration = flexypoolConfiguration();
return new FlexyPoolDataSource<>(
configuration,
new IncrementPoolOnTimeoutConnectionAcquiringStrategy.Factory<>(5),
new RetryConnectionAcquiringStrategy.Factory<>(2));
}
这个 FlexyPoolDataSource
在连接超时时向 Hikari 池添加额外的五个连接。如果池无法获取连接,它还会最多尝试两次重试连接。
最后,我们可以通过调用 FlexyPoolDataSource
运行我们的应用程序:
@SpringBootApplication
public class FlexypoolDemoApplication {
private static FlexyPoolDataSource<HikariDataSource> poolDataSource;
public FlexypoolDemoApplication(FlexyPoolDataSource<HikariDataSource> poolDataSource) {
FlexypoolDemoApplication.poolDataSource = poolDataSource;
}
public static List<Employee> getEmployees() throws SQLException {
String SQL_QUERY = "select * from emp";
List<Employee> employees;
try (Connection con = poolDataSource.getConnection(); PreparedStatement pst = con.prepareStatement(SQL_QUERY); ResultSet rs = pst.executeQuery();) {
employees = new ArrayList<>();
Employee employee;
while (rs.next()) {
employee = new Employee();
employee.setEmpNo(rs.getInt("empno"));
employee.setEname(rs.getString("ename"));
employee.setJob(rs.getString("job"));
employee.setMgr(rs.getInt("mgr"));
employee.setHiredate(rs.getDate("hiredate"));
employee.setSal(rs.getInt("sal"));
employee.setComm(rs.getInt("comm"));
employee.setDeptno(rs.getInt("deptno"));
employees.add(employee);
}
}
return employees;
}
public static void main(String[] args) throws SQLException {
SpringApplication.run(FlexypoolDemoApplication.class, args);
List<Employee> employees = getEmployees();
System.out.println(employees);
}
}
总结
在这篇文章中,我们了解了如何在 Spring Boot 和 H2 使用 HikariCP 连接池时使用 FlexyPool。
首先,我们了解了如何设置和配置 FlexyPool,以及如何监控其指标。
如往常一样,完整的源代码可以在 GitHub 上找到。