JDK7升级JDK11:Cassandra JDBC代码改造及HikariCP适配咨询
JDK7升级到JDK11:Cassandra JDBC代码优化与HikariCP接入方案
一、现有代码的JDK11适配升级
针对你的ConnectionManager代码,适配JDK11主要从过时API替换、并发安全优化、异常处理规范三个方向入手:
1. 替换JDK过时API
- 日期格式化:弃用线程不安全的
Calendar,改用JDK8+引入的java.time包类:// 原代码 CommonUtils.formatDate(Calendar.getInstance().getTime(),"dd-MM-yyyy HH:mm:ss") // 替换为 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss"); LocalDateTime.now().format(formatter) - 随机数生成:多线程环境下
Random存在性能瓶颈,改用ThreadLocalRandom:// 原代码 random.nextInt(hostsCopy.size()) // 替换为 ThreadLocalRandom.current().nextInt(hostsCopy.size()) - 线程睡眠:直接使用
Thread.sleep()替代Thread.currentThread().sleep(),语义更清晰。
2. 并发与性能优化
- 主机列表移除操作:原代码用
hostsCopy.remove(hostToTry)会遍历列表,效率低下,改为按索引移除:int idx = ThreadLocalRandom.current().nextInt(hostsCopy.size()); String hostToTry = hostsCopy.get(idx); // ...连接失败后 hostsCopy.remove(idx); - 单连接线程安全:现有代码用全局变量
con存储连接,多线程下会出现竞争问题,若不使用连接池,建议改为每次获取新连接,或用ThreadLocal存储线程专属连接。
3. 异常处理规范
- 移除
e.printStackTrace():改用日志框架输出完整异常栈,便于线上问题排查:// 原代码 e.printStackTrace(); // 替换为 LOG.error("连接主机失败: {}", hostToTry, e); - 处理中断状态:线程被中断时,恢复中断标记,避免后续逻辑丢失中断信号:
catch (InterruptedException e) { LOG.error("线程被中断", e); Thread.currentThread().interrupt(); // 恢复中断状态 throw new SQLException("线程中断导致连接失败", e); }
二、HikariCP连接池接入方案(强烈推荐)
完全可以使用HikariCP作为连接池方案,它是目前性能最优的JDBC连接池,完美兼容JDK11,还能大幅简化你的连接管理逻辑,自动处理负载均衡、故障转移、连接复用等场景。
1. 核心优势
- 自动管理连接生命周期,无需手动遍历主机重试
- 内置连接校验机制,确保获取的连接可用
- 高性能池化策略,减少连接创建销毁的开销
- 支持多主机配置,自动实现负载均衡
2. 实现步骤
(1)引入依赖
以Maven为例,添加HikariCP和兼容的Cassandra JDBC驱动依赖:
<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.0.1</version> <!-- 适配JDK11的最新稳定版 --> </dependency> <dependency> <groupId>com.datastax.cassandra</groupId> <artifactId>cassandra-jdbc-driver</artifactId> <version>3.1.0</version> <!-- 选择兼容你的Cassandra版本的驱动 --> </dependency>
(2)重构ConnectionManager
去掉原有的手动连接管理逻辑,改用HikariDataSource:
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ConnectionManager { private static final Logger LOG = LoggerFactory.getLogger(ConnectionManager.class); private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss"); private final HikariDataSource dataSource; private final int retries; private final long retrySleepMillis; // 构造函数接收连接参数 public ConnectionManager(String[] hosts, int thriftPort, String keyspace, int retries, long retrySleepMillis, int maxPoolSize, long connectionTimeout) { this.retries = retries; this.retrySleepMillis = retrySleepMillis; // 构建支持多主机的Cassandra JDBC URL StringBuilder jdbcUrl = new StringBuilder("jdbc:cassandra://"); for (int i = 0; i < hosts.length; i++) { if (i > 0) jdbcUrl.append(","); jdbcUrl.append(hosts[i]).append(":").append(thriftPort); } jdbcUrl.append("/").append(keyspace); // 配置HikariCP参数 HikariConfig config = new HikariConfig(); config.setJdbcUrl(jdbcUrl.toString()); // 若需认证,添加用户名密码 // config.setUsername("your-username"); // config.setPassword("your-password"); config.setMaximumPoolSize(maxPoolSize); // 连接池最大连接数 config.setConnectionTimeout(connectionTimeout); // 连接超时时间 config.setIdleTimeout(600000); // 空闲连接回收时间(10分钟) config.setMinimumIdle(5); // 最小空闲连接数 config.setConnectionTestQuery("SELECT now() FROM system.local"); // 连接有效性测试语句 this.dataSource = new HikariDataSource(config); } // 获取连接:直接从连接池获取,无需手动管理 private Connection getConnection() throws SQLException { LOG.debug("获取连接时间:{}", LocalDateTime.now().format(DATE_FORMATTER)); return dataSource.getConnection(); } // 执行查询:简化重试逻辑,借助连接池处理连接故障 public Pair<ResultSet, Statement> executeQuery(String query) throws SQLException { int retryCount = 0; while (retryCount < retries) { try (Connection con = getConnection(); Statement stmt = con.createStatement()) { ResultSet rs = stmt.executeQuery(query); // 注意:ResultSet和Statement需由调用方负责关闭,或改为返回结果集列表避免资源泄漏 return new Pair<>(rs, stmt); } catch (SQLTransientConnectionException e) { LOG.error("临时连接异常,重试次数:{}", retryCount, e); } catch (SQLNonTransientConnectionException e) { if (e.getCause() instanceof UnavailableException) { LOG.error("集群不可用,放弃重试", e); throw e; } else { LOG.error("执行查询异常,尝试重试", e); } } catch (SQLSyntaxErrorException e) { if (UnconfiguredColumnFamilyException.isUnconfiguredColumnFamilyException(e)) { throw new UnconfiguredColumnFamilyException(e); } else { throw e; } } retryCount++; try { Thread.sleep(retrySleepMillis); } catch (InterruptedException e) { LOG.error("线程被中断", e); Thread.currentThread().interrupt(); throw new SQLException("线程中断导致查询失败", e); } } LOG.error("重试次数耗尽,查询失败"); throw new RuntimeException(CommonServicesErrorConstants.CASSANDRA_DA_004); } // 关闭连接池 public void close() { if (dataSource != null) { dataSource.close(); } } }
(3)关键优化点
- 多主机配置:通过JDBC URL的逗号分隔列表实现,驱动和连接池会自动处理负载均衡和故障转移
- 连接复用:HikariCP会维护连接池,避免频繁创建销毁连接
- 连接校验:通过
connectionTestQuery确保获取的连接是可用的,无需手动检查连接状态
总结
- JDK11升级主要是替换过时API、优化并发和异常处理,解决原有代码的线程安全和性能问题
- HikariCP是非常适合的连接池方案,能大幅简化代码逻辑,提升系统的可靠性和性能,完全兼容JDK11和Cassandra JDBC
内容的提问来源于stack exchange,提问作者santhosh_athreya
相关产品推荐
相关产品推荐

