You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 22:05:24