DruidDataSource 封clickhouse实现数据操作

根据配置的服务器信息生成ClickHouse集群连接池

import cn.hutool.core.util.StrUtil;
import com.cloudwise.dcim.clickhouse.utils.ClickHouseClusterPool;
import com.cloudwise.dcim.clickhouse.utils.ClickHouseConnectionPool;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 **/
@Configuration
public class ClickHouseDruidConfig {
    
    @Value("${chServers}")
    private String servers;
    
    @Value("${chHttpPort:18100}")
    private Integer port;
    
    @Value("${chUsername:default}")
    private String user;
    
    @Value("${chPassword:Rootmaster@777}")
    private String password;
    
    /**
     * 根据配置的服务器信息生成ClickHouse集群连接池
     * 该方法用于初始化一个ClickHouseClusterPool实例,该实例包含了配置中所有ClickHouse服务器的连接池
     * 主要用于提高ClickHouse数据库的连接效率和管理连接资源
     *
     * @return ClickHouseClusterPool 返回一个包含所有ClickHouse服务器连接池的集群连接池对象
     */
    @Bean("clickHouseClusterPool")
    public ClickHouseClusterPool generationClusterPool() {
        // 将配置的服务器字符串按逗号分割成字符串数组
        String[] ipArray = servers.split(StrUtil.COMMA);
        // 创建一个ClickHouse集群连接池对象用于存储各个服务器的连接池
        ClickHouseClusterPool clickHouseClusterPool = new ClickHouseClusterPool();
        // 遍历服务器IP数组
        for (String ip : ipArray) {
            // 拼接ClickHouse数据库的JDBC连接URL
            String clickHouseUrl = "jdbc:clickhouse://" + ip + StrUtil.COLON + port;
            // 根据拼接的URL、用户名和密码创建ClickHouse连接池
            ClickHouseConnectionPool connectionPool = new ClickHouseConnectionPool(clickHouseUrl, user, password);
            // 将创建的连接池添加到集群连接池中
            clickHouseClusterPool.add(connectionPool);
        }
        // 返回包含所有服务器连接池的集群连接池对象
        return clickHouseClusterPool;
    }

    
   
    
}

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 **/
public class ClickHouseClusterPool {
    private  static final List<ClickHouseConnectionPool> CLUSTER_POOL= new ArrayList<>();
    
    /**
     * 随机获取一个ClickHouse连接池
     *
     * 本方法通过随机选择的方式从预定义的连接池集群中选取一个连接池,这样做的目的是为了均衡负载
     * 和提高系统的稳定性和可用性。通过这种方式,可以避免单点故障,并且使得对ClickHouse数据库
     * 的操作更加高效和可靠。
     *
     * @return ClickHouseConnectionPool 随机选择的ClickHouse连接池实例
     */
    public ClickHouseConnectionPool genClickHouseConnectionPool(){
        int index = new SecureRandom().nextInt(CLUSTER_POOL.size());
        return CLUSTER_POOL.get(index);
    }
    
    /**
     * ClickHouse连接池中添加一个新的连接池
     *
     * @param clickHouseConnectionPool 要添加的点击屋连接池对象
     */
    public void add(ClickHouseConnectionPool clickHouseConnectionPool){
        CLUSTER_POOL.add(clickHouseConnectionPool);
    }
    
    
}

import com.alibaba.druid.pool.DruidDataSource;

import java.sql.Connection;
import java.sql.SQLException;

/**
 **/
public class ClickHouseConnectionPool {
    private final DruidDataSource dataSource;
    
    public ClickHouseConnectionPool(String clickHouseUrl,String user,String paassword) {
         dataSource = new DruidDataSource();
    
        // 基本属性
        dataSource.setUrl(clickHouseUrl);
        dataSource.setUsername(user);
        dataSource.setPassword(paassword);
    
        // 配置初始化大小/最小/最大
        dataSource.setInitialSize(1);
        dataSource.setMinIdle(1);
        dataSource.setMaxActive(5);
    
        // 配置获取连接等待超时的时间
        dataSource.setMaxWait(600000);
    
        // 配置间隔多久进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        dataSource.setTimeBetweenEvictionRunsMillis(60000);
    
        // 配置一个连接在池中最小生存的时间,单位是毫秒
        dataSource.setMinEvictableIdleTimeMillis(300000);
    
        // 校验SQL,必要时会执行
        dataSource.setValidationQuery("SELECT 1");
        dataSource.setTestWhileIdle(true);
        dataSource.setTestOnBorrow(false);
        dataSource.setTestOnReturn(false);
    
        // 配置ClickHouse的Druid特有属性
        dataSource.setPoolPreparedStatements(false);
    
        try {
            dataSource.init();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
    /**
     * 获取数据库连接
     *
     * @return 数据库连接
     * @throws SQLException 如果无法获取连接,则抛出此异常
     */
    public Connection getConnection() throws SQLException {
        try {
            // 通过数据源获取数据库连接
            return dataSource.getConnection();
        } catch (Exception e) {
            // 捕获异常并包装成SQLException抛出,以便调用者能够处理获取连接失败的情况
            throw new SQLException("Could not get a connection", e);
        }
    }
    
    /**
     * 归还数据库连接到连接池
     *
     * @param conn 要归还的数据库连接对象
     */
    public void returnConnection(Connection conn) {
        if (conn != null) {
            try {
                //归还连接到DruidDataSource
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    
}

SQL模版解析

import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.StringTemplateResourceLoader;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 **/
public class BeetlTemplateUtils {
    private static GroupTemplate gt;
    static {
        //初始化代码
        StringTemplateResourceLoader resourceLoader = new StringTemplateResourceLoader();
        Configuration cfg = null;
        try {
            cfg = Configuration.defaultConfiguration();
        } catch (IOException e) {
            e.printStackTrace();
        }
        gt = new GroupTemplate(resourceLoader, cfg);
    }
    
    
    /**
     * 根据给定的模板和参数渲染字符串
     *
     * @param template 模板名称,用于查找对应的模板
     * @param params 参数映射,包含需要替换在模板中的键值对
     * @return 渲染后的字符串
     */
    public static String render(String template, Map<String,? extends Object> params){
        // 获取模板
        Template t = gt.getTemplate(template);
        // 如果参数映射不为空且不为空,则遍历参数并将其绑定到模板中
        if(params != null && !params.isEmpty()){
            params.forEach((key,value)->{
                t.binding(key, value);
            });
        }
        // 返回渲染后的字符串
        return  t.render();
    }
    
    public static void main(String[] args) throws IOException {
        
        String template = "hello,${name}";
        Map<String,String> params = new HashMap<>();
        params.put("name","Lucy");
        // 输出渲染后的字符串
        System.out.println(BeetlTemplateUtils.render(template,params));
   
    }

}

CK具体操作

import cn.hutool.json.JSONUtil;
import com.cloudwise.dcim.common.exception.BaseException;
import com.cloudwise.dcim.common.utils.SpringHoldUtil;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 **/
@Slf4j
public class ClickHouseQueryUtils {
    /**
     * 执行SQL查询,并返回查询结果的列表
     * 该方法直接返回查询结果的Map列表,不涉及实体类转换
     *
     * @param sql 查询的SQL语句
     * @return 包含查询结果的Map列表,每条记录作为一个Map对象
     * @throws BaseException 当查询过程中发生SQLException时,抛出自定义的BaseException
     *
     */
    public static List<Map<String,Object>> querySelect(String sql){
        ClickHouseConnectionPool connectionPool =  SpringHoldUtil.getBean(ClickHouseClusterPool.class).genClickHouseConnectionPool();
        Connection connection = null;
        //输入动态参数
        //PreparedStatement preparedStatement = null;
        List<Map<String, Object>> dataMap = null;
        
        try {
            connection = connectionPool.getConnection();
            //preparedStatement = connection.prepareStatement() ;
            sql = BeetlTemplateUtils.render(sql,null);
            try(Statement statement = connection.createStatement()){
                long currentTime = System.currentTimeMillis();
                try (ResultSet resultSet = statement.executeQuery(sql)) {
                    long endTime = System.currentTimeMillis();
                    //大于10秒是慢SQL
                    if(endTime-currentTime>10000){
                        log.error("CK慢SQL用时{}毫秒SQL语句:{}",(endTime-currentTime),sql);
                    }
                    // 处理结果集
                    dataMap = convert(resultSet);
                }
            }
        }catch (SQLException e){
            throw  new BaseException(e);
        }finally {
            if(connection!=null) {
                connectionPool.returnConnection(connection);
            }
        }
        return  dataMap;
    }

    /**
     * 根据SQL模板和参数查询数据
     *
     * @param sqlTemplate SQL模板,使用Beetl模板语法编写
     * @param params 参数映射,键为模板中的变量名,值为变量的值
     * @return 查询结果列表,每个结果为一个键值对映射
     *
     * 本方法通过BeetlTemplateUtils工具类渲染SQL模板,将params参数中的键值对替换到sqlTemplate中,
     * 生成最终的SQL查询语句,然后执行该查询语句,返回查询到的数据
     *
     */
    public static List<Map<String,Object>> querySelect(String sqlTemplate, Map<String,? extends Object> params){
        // 渲染SQL模板,生成最终的SQL查询语句
        String sql = BeetlTemplateUtils.render(sqlTemplate,params);
        // 执行SQL查询,并返回查询结果
        return querySelect(sql);
    }
    /**
     * 根据提供的SQL语句和实体类类型,查询数据库并转换结果为指定实体类的列表
     * 此方法用于执行查询操作,而不直接返回数据库查询结果集,而是将结果集映射为实体对象列表
     * 它利用了JSONUtil库来实现从数据库查询结果到实体类实例列表的转换
     *
     * @param sql 查询数据库的SQL语句
     * @param cls 实体类的Class对象,用于将查询结果转换为目标实体类列表
     * @param <T> 实体类类型
     * @return 返回类型为T的实体类对象列表如果查询结果为空或转换失败,则返回null
     */
    public static  <T> List<T> querySelect(String sql,Class<T> cls) {
        // 执行SQL查询,返回结果集为List<Map<String, Object>>类型
        List<Map<String, Object>> dataMap =  querySelect(sql);
        
        // 检查查询结果是否非空且不为空列表
        if(dataMap!=null&&!dataMap.isEmpty()) {
            // 将查询结果Map列表转换为JSON字符串
            String jsonData = JSONUtil.toJsonStr(dataMap);
            // 将JSON字符串转换为指定实体类的列表并返回
            return  JSONUtil.toList(jsonData, cls);
        }
        // 如果查询结果为空或转换过程出错,则返回null
        return  null;
    }

    
    /**
     * 使用模板和参数执行SQL查询,并将结果映射到指定的实体类列表中
     * 该方法使用Beetl模板引擎将sqlTemplate与params中的参数合并生成SQL语句,
     * 然后执行该SQL语句,并将结果集转换为由泛型类型T指定的实体类列表
     *
     * @param sqlTemplate SQL模板,可以包含Beetl模板语法,用于动态生成SQL
     * @param params 参数映射,键为模板中的参数名称,值为参数的实际值
     * @param cls 实体类类型,用于将查询结果映射到该类型对象
     * @param <T> 泛型类型,表示实体类类型
     * @return 包含查询结果的实体类对象列表如果查询结果为空或没有匹配的记录,则返回空列表
     */
    public static <T> List<T> querySelect(String sqlTemplate, Map<String,? extends Object> params,Class<T> cls){
        // 根据SQL模板和参数,利用Beetl模板引擎渲染生成最终的SQL语句
        String sql = BeetlTemplateUtils.render(sqlTemplate,params);
        // 调用重载的querySelect方法,执行SQL查询,并将结果映射到指定的实体类
        return querySelect(sql,cls);
    }

    
    /**
     * 将数据库查询结果集转换为包含列-值对的列表
     * 此方法用于将 JDBC ResultSet 对象转换为 List<Map<String, Object>> 形式
     * 这种形式更方便在应用程序中处理和访问查询结果
     *
     * @param rs ResultSet 对象,包含数据库查询结果
     * @return 一个 List 对象,其中每个元素是一个 Map,表示查询结果的一行,键为列名,值为该列的值
     * @throws SQLException 如果处理 ResultSet 过程中出现错误,将抛出此异常
     */
    private static List<Map<String, Object>> convert(ResultSet rs) throws SQLException {
        // 获取结果集的元数据,元数据包含表结构的信息,如列名和数据类型
        ResultSetMetaData md = rs.getMetaData();
        // 获取结果集的列数
        int columns = md.getColumnCount();
        // 初始化一个列表,用于存储查询结果的每一行的数据
        List<Map<String, Object>> list = new ArrayList<>();
        // 遍历结果集的每一行,直到 rs.next() 返回 false 为止
        while (rs.next()) {
            // 初始化一个映射,用于存储当前行的列名和值对
            Map<String, Object> row = new HashMap<>(columns);
            // 遍历当前行的每一列,将列名和值存入映射
            for (int i = 1; i <= columns; ++i) {
                // 调用 rs.getObject 方法获取当前列的值,并以列名为键存入映射
                row.put(md.getColumnName(i), rs.getObject(i));
            }
            // 将当前行的映射添加到列表中
            list.add(row);
        }
        // 返回存储查询结果的列表
        return list;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/901670.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大语言模型的Scaling Law【Power Low】

NLP-大语言模型学习系列目录 一、注意力机制基础——RNN,Seq2Seq等基础知识 二、注意力机制【Self-Attention,自注意力模型】 三、Transformer图文详解【Attention is all you need】 四、大语言模型的Scaling Law【Power Low】 文章目录 NLP-大语言模型学习系列目录一、什么是…

隧道煤矿甬道的可视化大屏,关键时刻起关键作用

隧道、煤矿甬道的可视化大屏在关键时刻确实能发挥关键作用。它可以实时显示内部的环境参数&#xff0c;如温度、湿度、瓦斯浓度等&#xff0c;帮助工作人员及时掌握潜在危险情况。 同时&#xff0c;大屏能展示人员分布和设备运行状态&#xff0c;便于高效调度和管理。 在紧急…

计算机网络:网络层 —— IPv4 地址与 MAC 地址 | ARP 协议

文章目录 IPv4地址与MAC地址的封装位置IPv4地址与MAC地址的关系地址解析协议ARP工作原理ARP高速缓存表 IPv4地址与MAC地址的封装位置 在数据传输过程中&#xff0c;每一层都会添加自己的头部信息&#xff0c;最终形成完整的数据包。具体来说&#xff1a; 应用层生成的应用程序…

技术成神之路:设计模式(二十一)外观模式

相关文章&#xff1a;技术成神之路&#xff1a;二十三种设计模式(导航页) 介绍 外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它为子系统中的一组接口提供一个统一的接口。外观模式定义了一个高层接口&#xff0c;使得子系统更容易使用。 …

qt QGraphicsGridLayout详解

一、概述 QGraphicsGridLayout是Qt框架中用于在QGraphicsScene中布置图形项的一个布局管理器。它类似于QWidget中的QGridLayout&#xff0c;但主要处理的是QGraphicsItem和QGraphicsWidget等图形项。通过合理设置网格位置、伸缩因子和尺寸&#xff0c;可以实现复杂而灵活的布局…

【论文笔记】MLSLT: Towards Multilingual Sign Language Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: MLSLT: Towards Multiling…

2024-网鼎杯第二次模拟练习-web02

进入做题页面&#xff0c;经过信息搜集和目录扫描&#xff0c;发现只有一个公告是可以利用的 http://0192c74e0f9871c2956795c804c3dde3.8nfp.dg01.wangdingcup.com:43014/OA_announcement.php?id1 这个后面有一个明显的注入点&#xff0c;经过多次刷新和快速刷新后发现&…

使用FRP搭建内网穿透服务(新版toml配置文件,搭配反向代理方便内网网站访问)【使用frp搭建内网穿透】

FRP&#xff08;Fast Reverse Proxy&#xff09;是一个高性能的反向代理应用程序&#xff0c;主要用于内网穿透。它允许用户将内部网络服务暴露到外部网络&#xff0c;适用于 NAT 或防火墙环境下的服务访问。 他是一个开源的 服务 如果大家不想用 花生壳 软件&#xff0c;可以尝…

基于信号分解和多种深度学习结合的上证指数预测模型

大家好&#xff0c;我是带我去滑雪&#xff01; 为了给投资者提供更准确的投资建议、帮助政府和监管部门更好地制定相关政策&#xff0c;维护市场稳定&#xff0c;本文对股民情绪和上证指数之间的关系进行更深入的研究&#xff0c;并结合信号分解、优化算法和深度学习对上证指数…

探索孤独症儿童治愈的希望之路

孤独症&#xff0c;作为一种严重影响儿童发展的神经发育障碍性疾病&#xff0c;给无数家庭带来了难以承受的沉重负担。然而&#xff0c;人们始终未曾放弃对孤独症儿童治愈可能性的不懈探索。 早期干预乃是关键所在。一旦儿童被诊断为孤独症&#xff0c;就应迅速启动全面且系统的…

分类预测 | GCN图卷积神经网络多特征分类预测(MATLAB)

分类预测 | GCN图卷积神经网络多特征分类预测(MATLAB) 目录 分类预测 | GCN图卷积神经网络多特征分类预测(MATLAB)分类效果基本介绍程序设计参考资料分类效果 基本介绍 GCN图卷积神经网络多特征分类预测(MATLAB) 在图卷积神经网络(GCN)中,多特征分类

orange pi开启vnc服务,并使用mac远程连接

先输入vncserver看一下是否开启了vnc服务&#xff0c;如果提示输入密码&#xff0c;就是正在开启&#xff0c;然后选择只是查看权限还是也有控制权限&#xff0c;肯定要控制阿&#xff0c;所以选择n。 或者输入&#xff1a;sudo netstat -pl | grep vnc 如果能找到vnc的进程&a…

ThriveX 现代化博客管理系统

ThriveX 现代化博客管理系统 &#x1f389; &#x1f525; 首先最重要的事情放第一 开源不易&#xff0c;麻烦占用 10 秒钟的时间帮忙点个免费的 Star&#xff0c;再此万分感谢&#xff01; 下面开始进入主题↓↓↓ &#x1f308; 项目介绍&#xff1a; Thrive 是一个简而不…

生活中是否害怕过机械硬盘出现坏道?

目录 一、坏道起因 二、继续了解-系统对坏扇区的处理 &#xff08;一&#xff09;硬盘自身的处理机制 &#xff08;二&#xff09;操作系统层面的处理 三、进一步了解-备用扇区 &#xff08;一&#xff09;备用扇区的工作原理 &#xff08;二&#xff09;S.M.A.R.T.技术…

DMVPN协议

DMVPN&#xff08;Dynamic Multipoint VPN&#xff09;动态多点VPN 对于分公司和分总公司内网实现通信环境下&#xff0c;分公司是很多的。我们不可能每个分公司和总公司都挨个建立ipsec隧道 &#xff0c;而且如果是分公司和分公司建立隧道&#xff0c;就会很麻烦。此时我们需…

【单运放可调频率正弦波电路二阶RC移相震荡文氏桥】2021-12-20

缘由想让正弦波频率是1K赫兹到100K赫兹应该怎么调节滑动变阻器&#xff0c;计算起来感觉不对劲-嵌入式-CSDN问答 调节R12负反馈让波形不出现销顶失真&#xff0c;同时负反馈深度影响输出幅值&#xff0c;调节频率范围有限&#xff0c;频率越高越不稳定。 RC移相式振荡器文氏电…

ThinkPHP+Mysql 灵活用工+灵活用工平台+灵活用工系统

基于 ThinkPHPMysql 灵活用工灵活用工平台灵活用工系统灵活用工小程序灵活用工源码灵活用工系统源码 开发语言 ThinkPHPMysql 源码合作 提供完整源代码 软件界面展示 一、企业管理后台 二、运用管理平台 三、手机端

vue文件报Cannot find module ‘webpack/lib/RuleSet‘错误处理

检查 Node.js 版本&#xff1a;这个问题可能与 Node.js 的版本有关。你可以尝试将 Node.js 的版本切换到 12 或更低。如果没有安装 nvm&#xff08;Node Version Manager&#xff09;&#xff0c;可以通过以下命令安装&#xff1a; curl -o- https://raw.githubusercontent.co…

Docker 安装使用

1. 下载 下载地址&#xff1a;Index of linux/static/stable/x86_64/ 下载好后&#xff0c;将文件docker-18.06.3-ce.tgz用WinSCP等工具&#xff0c;上传到不能外网的linux系统服务器 2. 安装 解压后的文件夹docker中文件如下所示&#xff1a; 将docker中的全部文件&#xff…

基于云平台的智能家居管理系统设计与通信协议分析

案例 阅读以下关于 Web 系统架构设计的教述&#xff0c;在答题纸上回答问题1至问题3。 【说明】 某公司拟开发一个智能家居管理系统&#xff0c;该系统的主要功能需求如下: 1)用户可使用该系统客户端实现对家居设备的控制&#xff0c;且家居设备可向客户端反馈实时状态&#x…