go-zero整合单机版ClickHouse并实现增删改查

go-zero整合单机版ClickHouse并实现增删改查

本教程基于go-zero微服务入门教程,项目工程结构同上一个教程。

本教程主要实现go-zero框架整合单机版ClickHouse,并暴露接口实现对ClickHouse数据的增删改查。

go-zero微服务入门教程:https://blog.csdn.net/u011019141/article/details/136233473
本文源码:https://gitee.com/songfayuan/go-zero-demo (教程源码分支:5.zero整合单机ClickHouse)

准备工作

  • 如不熟悉go-zero项目的,请先查看上一篇go-zero微服务入门教程
  • 请自行安装好单机版ClickHouse,建议采用docker安装。

安装依赖

项目工程父级目录下执行如下指令安装依赖:

# 下载安装clickhouse-go
go get github.com/ClickHouse/clickhouse-go/v2
# 下载安装otel/sdk/trace
go get -u go.opentelemetry.io/otel/sdk/trace

rpc新增ClickHouse配置

以下操作在rpc模块执行。

sys.yaml

sys.yaml配置文件新增ClickHouse配置信息,如下:

# ClickHouse配置
ClickHouse:Addr:- "192.168.2.204:9000"Auth:Database: dsmsUsername: defaultPassword:Table: http_captureInterval: 3MaxNum: 1000MaxChunkBytes: 10485760Debug: falseDatasource: clickhouse://default:@192.168.2.204:9000/dsms?debug=false

config.go

config.go文件中新增ClickHouseConf配置信息,如下:

package configimport ("github.com/zeromicro/go-zero/zrpc""go-zero-demo/common/task/kafkaconf"
)type Config struct {zrpc.RpcServerConfClickHouse ClickHouseConf
}type ClickHouseAuthConf struct {Database stringUsername stringPassword string `json:",optional"`
}type ClickHouseConf struct {Addr []stringAuth ClickHouseAuthConfOpt1 struct {MaxIdleConns int `json:",optional"`MaxOpenConns int `json:",optional"`} `json:",optional"`Opt2 struct {MaxIdleConns int `json:",optional"`MaxOpenConns int `json:",optional"`} `json:",optional"`Table   stringColumns []string `json:",optional"`Debug   bool     `json:",default=false"`Datasource string `json:",optional,default="`
}

servicecontext.go

servicecontext.go文件新增ClickHouse配置信息,完整代码如下:

package serverimport ("github.com/ClickHouse/clickhouse-go/v2""go-zero-demo/rpc/sys/internal/config""log""time"
)type ServiceContext struct {Config      config.ConfigClickhouseConn clickhouse.Conn
}func NewServiceContext(c config.Config) *ServiceContext {return &ServiceContext{Config:      c,ClickhouseConn: NewClickHouseConn(c.ClickHouse),}
}// NewClickHouseConn 创建clickhouse链接 【clickhouse-go】
func NewClickHouseConn(ckConfig config.ClickHouseConf) clickhouse.Conn {maxIdleConns := 20if ckConfig.Opt2.MaxIdleConns > 0 {maxIdleConns = ckConfig.Opt2.MaxIdleConns}maxOpenConns := 2000if ckConfig.Opt2.MaxOpenConns > 0 {maxOpenConns = ckConfig.Opt2.MaxOpenConns}conn, err := clickhouse.Open(&clickhouse.Options{Addr: ckConfig.Addr,Auth: clickhouse.Auth{Database: ckConfig.Auth.Database,Username: ckConfig.Auth.Username,Password: ckConfig.Auth.Password,},Settings: clickhouse.Settings{"max_execution_time": 60,},DialTimeout:  30 * time.Second,MaxIdleConns: maxIdleConns,MaxOpenConns: maxOpenConns,Debug:        ckConfig.Debug,})if err != nil {log.Fatalf("error: 启动clickhouse client失败, %v", err)}return conn
}

编写rpc服务

修改sys.proto文件

新增ClickHouse操作请求的配置,如下:

message ClickhouseReq{string name = 1;string nickName = 2;string password = 3;string email = 4;
}message  ClickhouseResp{string name = 1;string nickName = 2;string password = 3;string email = 4;
}service Sys{// clickhouse增删改查rpc ClickhouseAdd(ClickhouseReq)returns(ClickhouseResp);rpc ClickhouseDelete(ClickhouseReq)returns(ClickhouseResp);rpc ClickhouseUpdate(ClickhouseReq)returns(ClickhouseResp);rpc ClickhouseGet(ClickhouseReq)returns(ClickhouseResp);
}

用goctl生成rpc代码

生成方法同上篇文章,自行查看。

编写API Gateway代码

编写api文件

clickhouse.api

在api目录下创建新目录doc/clickhouse,在clickhouse目录下创建clickhouse.api文件。

syntax = "v1"info(title: "clickhouse操作相关"desc: "clickhouse操作相关"author: "宋发元"
)type (ApiClickhouseReq {Name     string `json:"name"`NickName string `json:"nickName"`Password string `json:"password,optional"`Email    string `json:"email"`}ApiClickhouseResp {Code    int64       `json:"code"`Message string      `json:"message"`Data    ApiClickhouseReq `json:"data"`}ApiClickhouseGetReq {Key string `form:"key"`}
)@server (group : clickhouse/testprefix : /clickhouse/test
)service admin-api{@doc(summary : "Clickhouse新增数据")@handler ClickhouseAddpost /clickhouseAdd(ApiClickhouseReq)returns(ApiClickhouseResp)@doc(summary : "Clickhouse删除数据")@handler ClickhouseDeletepost /clickhouseDelete(ApiClickhouseReq)returns(ApiClickhouseResp)@doc(summary : "Clickhouse修改数据")@handler ClickhouseUpdatepost /clickhouseUpdate(ApiClickhouseReq)returns(ApiClickhouseResp)@doc(summary : "Clickhouse查询数据")@handler ClickhouseGetget /clickhouseGet(ApiClickhouseGetReq)returns(ApiClickhouseResp)
}
admin.api

在api/doc/admin.api文件添加配置信息。

import "clickhouse/clickhouse.api"

用goctl生成API Gateway代码

生成方法同上篇文章,自行查看。但是此处要基于admin.api文件去生成代码,如果基于clickhouse.api生成,则生成的代码只有clickhouse.api定义的接口代码,其他api文件定义的接口代码不被生成。

修改API Gateway代码调用rpc服务

clickhouseaddlogic.go

修改api/internal/logic/clickhouse/test/clickhouseaddlogic.go里的ClickhouseAdd方法,如下:

func (l *ClickhouseAddLogic) ClickhouseAdd(req *types.ApiClickhouseReq) (resp *types.ApiClickhouseResp, err error) {res, err := l.svcCtx.Sys.ClickhouseAdd(l.ctx, &sysclient.ClickhouseReq{Name:     req.Name,NickName: req.NickName,Password: req.Password,Email:    req.Email,})if err != nil {reqJson, _ := json.Marshal(res)logx.WithContext(l.ctx).Errorf("新增Clickhouse信息失败,请求参数:%s,异常信息:%s", reqJson, err.Error())return nil, rpcerror.New(err)}return &types.ApiClickhouseResp{Code:    200,Message: "新增成功",Data: types.ApiClickhouseReq{Name:     req.Name,NickName: req.NickName,Password: req.Password,Email:    req.Email,},}, nil
}

clickhousedeletelogic.go

修改api/internal/logic/clickhouse/test/clickhousedeletelogic.go里的ClickhouseDelete方法,如下:

func (l *ClickhouseDeleteLogic) ClickhouseDelete(req *types.ApiClickhouseReq) (resp *types.ApiClickhouseResp, err error) {l.svcCtx.Sys.ClickhouseDelete(l.ctx, &sysclient.ClickhouseReq{})return &types.ApiClickhouseResp{Code:    200,Message: "删除成功",Data:    types.ApiClickhouseReq{},}, nil
}

clickhousegetlogic.go

修改api/internal/logic/clickhouse/test/clickhousegetlogic.go里的ClickhouseGet方法,如下:

func (l *ClickhouseGetLogic) ClickhouseGet(req *types.ApiClickhouseGetReq) (resp *types.ApiClickhouseResp, err error) {param := &sysclient.ClickhouseReq{}copier.Copy(param, req)getRes, err := l.svcCtx.Sys.ClickhouseGet(l.ctx, param)if err != nil {resJson, _ := json.Marshal(getRes)logx.WithContext(l.ctx).Errorf("获取数据测试:操作失败,请求参数param = %s,异常信息errMsg = %s", resJson, err.Error())return nil, rpcerror.New(err)}return &types.ApiClickhouseResp{Code:    200,Message: "操作成功",Data: types.ApiClickhouseReq{Name:     getRes.Name,NickName: getRes.NickName,Password: getRes.Password,Email:    getRes.Email,},}, nil
}

clickhouseupdatelogic.go

修改api/internal/logic/clickhouse/test/clickhouseupdatelogic.go里的ClickhouseUpdate方法,如下:

func (l *ClickhouseUpdateLogic) ClickhouseUpdate(req *types.ApiClickhouseReq) (resp *types.ApiClickhouseResp, err error) {updateRes, err := l.svcCtx.Sys.ClickhouseUpdate(l.ctx, &sysclient.ClickhouseReq{Name:     req.Name,NickName: req.NickName,Password: req.Password,Email:    req.Email,})if err != nil {resJson, _ := json.Marshal(updateRes)logx.WithContext(l.ctx).Errorf("Clickhouse更新数据测试:操作失败,请求参数param = %s,异常信息errMsg = %s", resJson, err.Error())return nil, rpcerror.New(err)}return &types.ApiClickhouseResp{Code:    200,Message: "操作成功",Data: types.ApiClickhouseReq{Name:     updateRes.Name,NickName: updateRes.NickName,Password: updateRes.Password,Email:    updateRes.Email,},}, nil
}

修改rpc代码调用crud代码

clickhouseaddlogic.go

  • 修改rpc/sys/internal/logic/clickhouseaddlogic.go,如下内容:
// clickhouse增删改查
func (l *ClickhouseAddLogic) ClickhouseAdd(in *sysclient.ClickhouseReq) (*sysclient.ClickhouseResp, error) {// 创建表createTable(l.ctx, l.svcCtx.ClickhouseConn)// 插入数据insertData(l.ctx, l.svcCtx.ClickhouseConn, "Alice", "Ally", "password123", "alice@example.com")insertData(l.ctx, l.svcCtx.ClickhouseConn, "Bob", "Bobby", "password456", "bob@example.com")// 批量插入数据batchInsertData(l.ctx, l.svcCtx.ClickhouseConn, []User{{"Alice", "Ally", "password123", "alice@example.com"},{"Bob", "Bobby", "password456", "bob@example.com"},{"Charlie", "Char", "password789", "charlie@example.com"},})return &sysclient.ClickhouseResp{}, nil
}// 创建表
func createTable(ctx context.Context, conn clickhouse.Conn) {query := `CREATE TABLE IF NOT EXISTS demo (Name String,NickName String,Password String,Email String) ENGINE = MergeTree()ORDER BY Name`err := conn.Exec(ctx, query)if err != nil {log.Fatal(err)}fmt.Println("成功创建demo表...")
}// 插入数据
func insertData(ctx context.Context, conn clickhouse.Conn, name, nickName, password, email string) {batch, err := conn.PrepareBatch(ctx, "INSERT INTO demo (Name, NickName, Password, Email)")if err != nil {log.Fatal(err)}err = batch.Append(name, nickName, password, email)if err != nil {log.Fatal(err)}err = batch.Send()if err != nil {log.Fatal(err)}fmt.Println("成功插入数据...")
}// 批量插入数据
func batchInsertData(ctx context.Context, conn clickhouse.Conn, users []User) {batch, err := conn.PrepareBatch(ctx, "INSERT INTO demo (Name, NickName, Password, Email)")if err != nil {log.Fatal(err)}for _, user := range users {err := batch.Append(user.Name, user.NickName, user.Password, user.Email)if err != nil {log.Fatal(err)}}err = batch.Send()if err != nil {log.Fatal(err)}fmt.Println("成功批量插入数据...")
}

clickhousedeletelogic.go

  • 修改rpc/sys/internal/logic/clickhousedeletelogic.go,如下内容:
func (l *ClickhouseDeleteLogic) ClickhouseDelete(in *sysclient.ClickhouseReq) (*sysclient.ClickhouseResp, error) {// 删除数据deleteData(l.ctx, l.svcCtx.ClickhouseConn, "Bob")return &sysclient.ClickhouseResp{}, nil
}// 删除数据
func deleteData(ctx context.Context, conn clickhouse.Conn, name string) {query := `ALTER TABLE demo DELETE WHERE Name = ?`err := conn.Exec(ctx, query, name)if err != nil {log.Fatal(err)}fmt.Println("删除数据成功...")
}

clickhouseupdatelogic.go

  • 修改rpc/sys/internal/logic/clickhouseupdatelogic.go,如下内容:
func (l *ClickhouseUpdateLogic) ClickhouseUpdate(in *sysclient.ClickhouseReq) (*sysclient.ClickhouseResp, error) {// 更新数据updateData(l.ctx, l.svcCtx.ClickhouseConn, "Alice", "newpassword321")return &sysclient.ClickhouseResp{}, nil
}// 更新数据
func updateData(ctx context.Context, conn clickhouse.Conn, name, newPassword string) {query := `ALTER TABLE demo UPDATE Password = ? WHERE Name = ?`err := conn.Exec(ctx, query, newPassword, name)if err != nil {log.Fatal(err)}fmt.Println("Data updated successfully")
}

clickhousegetlogic.go

  • 修改rpc/sys/internal/logic/clickhousegetlogic.go,如下内容:
func (l *ClickhouseGetLogic) ClickhouseGet(in *sysclient.ClickhouseReq) (*sysclient.ClickhouseResp, error) {// 查询数据queryData(l.ctx, l.svcCtx.ClickhouseConn)return &sysclient.ClickhouseResp{}, nil
}// 查询数据
func queryData(ctx context.Context, conn clickhouse.Conn) {rows, err := conn.Query(ctx, "SELECT Name, NickName, Password, Email FROM demo")if err != nil {log.Fatal(err)}defer rows.Close()for rows.Next() {var name, nickName, password, email stringif err := rows.Scan(&name, &nickName, &password, &email); err != nil {log.Fatal(err)}fmt.Printf("Name: %s, NickName: %s, Password: %s, Email: %s\n", name, nickName, password, email)}
}

完整调用演示

最后,在根目录go-zero-demo执行下命令。

go mod tidy

运行rpc服务

运行方法同上篇文章,具体查看教程go-zero微服务入门教程完整调用演示部分。

运行api

运行方法同上篇文章,具体查看教程go-zero微服务入门教程完整调用演示部分。

api调用

以下调用采用curl进行,你也可以用postman调用。

新增接口
 songfayuan@MacBook-Pro  ~  curl -X POST -H "Content-Type: application/json" -d '{"name":"songfayuan","nickName":"宋发元","email":"1414@qq.com"}' localhost:8888/clickhouse/test/clickhouseAdd{"code":200,"message":"操作成功","data":{"name":"songfayuan","nickName":"宋发元","password":"","email":"1414@qq.com"}}%
删除接口
 songfayuan@MacBook-Pro  ~  curl -X POST -H "Content-Type: application/json" -d '{"name":"songfayuan","nickName":"宋发元6666","email":"1414@qq.com"}' localhost:8888/clickhouse/test/clickhouseDelete{"code":200,"message":"操作成功","data":{"name":"","nickName":"","password":"","email":""}}%
修改接口
 songfayuan@MacBook-Pro  ~  curl -X POST -H "Content-Type: application/json" -d '{"name":"songfayuan","nickName":"宋发元6666","email":"1414@qq.com"}' localhost:8888/clickhouse/test/clickhouseUpdate{"code":200,"message":"操作成功","data":{"name":"songfayuan","nickName":"宋发元6666","password":"","email":"1414@qq.com"}}%
查询接口
 songfayuan@MacBook-Pro  ~  curl "localhost:8888/clickhouse/test/clickhouseGet?key=121212"{"code":200,"message":"操作成功","data":{"name":"songfayuan","nickName":"宋发元6666","password":"","email":"1414@qq.com"}}%

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用python将多个EXCEL表进行合并

在Python中,你可以使用pandas库来轻松地将多个Excel表格合并。以下是一个基本的步骤指南和示例代码,说明如何合并多个Excel文件到一个单独的DataFrame中: 步骤 安装pandas和openpyxl(如果你正在处理.xlsx文件)。导入…

Microservices with Martin Fowler

Summary The article “Microservices” by Martin Fowler discusses an architectural style for software systems that has been gaining popularity due to its flexibility and scalability. Here’s a summary highlighting the key points: Microservice Architectural…

通过Validator接口实现参数校验

一、自定义类实现Validator接口 重写supports和validate这两个方法&#xff0c;在supports中写你要需校验的参数&#xff0c;在validate中定义你需要校验的规则 public class WarehouseAreaValidator implements Validator {Overridepublic boolean supports(Class<?>…

贪吃蛇游戏的编程之旅:在Windows PyCharm中使用Python

在电脑游戏的发展史中,贪吃蛇游戏无疑是其中的经典之作。许多人对其简单而上瘾的游戏玩法念念不忘。对编程爱好者来说,重新编写一个贪吃蛇游戏不仅是对青春回忆的一种致敬,也是一个极佳的学习机会。本文将引导你在Windows系统的PyCharm环境下,使用Python和pygame库来实现这…

jackson 若干问

jackson 若干问 https://www.jianshu.com/p/7a4653704acb https://cloud.tencent.com/developer/article/2394800 https://developer.aliyun.com/article/1001646 https://stackoverflow.com/questions/24280605/how-to-create-json-array-using-jackson https://www.bael…

Unity内制作动画

Unity内制作动画 动画剪辑&#xff08;Animation Clips&#xff09; 创建动画剪辑&#xff1a;在Unity中&#xff0c;可以通过导入动画数据来创建动画剪辑。这些数据可以是FBX、OBJ等格式的3D模型文件&#xff0c;其中包含关键帧动画。 编辑动画剪辑&#xff1a;在Unity的Anim…

最新一站式AI创作中文系统网站源码+系统部署+支持GPT对话、Midjourney绘画、Suno音乐、GPT-4o文档分析等大模型

一、系统简介 本文将介绍最新的一站式AI创作中文系统&#xff08;集成ChatGPTMidjourneySunoStable Diffusion&#xff09;——星河易创AI系统&#xff0c;该系统基于ChatGPT的核心技术&#xff0c;融合了自然语言问答、绘画、音乐、文档分享、图片识别等创作功能&#xff0c;…

牛客热题:数组中出现一次的两个数字

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题&#xff1a;数组中出现一次的两个数字题目链…

开发Windows应用程序的多种工具和语言

在软件开发领域&#xff0c;Windows应用程序的开发是一个广泛而多样化的领域。开发者可以利用各种工具和编程语言来创建功能丰富、用户友好的应用程序。以下是一些常见的开发环境和编程语言&#xff0c;它们被广泛用于开发Windows应用程序。 Visual Studio&#xff1a;微软的集…

集成学习算法笔记

一、引言 在机器学习和数据分析领域&#xff0c;集成学习算法因其能够显著提高模型预测性能而备受关注。然而&#xff0c;任何算法在应用过程中都不可避免地会遇到一些挑战和问题&#xff0c;集成学习算法也不例外。其中&#xff0c;最为常见且关键的两大问题便是欠拟合&#…

全国水系数据(更新到2024年5月)

上海市水系数据地图可视化 水系数据线图层&#xff08;小河/溪流、江/河、运河、下水道/排水管&#xff09; 水系数据面数据&#xff08;水域、水库、河岸、湿地&#xff09; 水系数据字段说明 可视化预览 北京市水系可视化 上海市水系可视化 广州市水系可视化 深圳市水系可视化…

考研数学考到110+分,到底有多难?

很难&#xff01; 大家平时在网上上看到很多人说自己考了130&#xff0c;其实这些人只占参加考研数学人数的极少部分&#xff0c;有个数据可以展示出来考研数学到底有多难&#xff1a; 在几百万考研大军中&#xff0c;能考到120分以上的考生只有2%。绝大多数人的分数集中在30…

Django 注册应用

上一章Django 创建项目及应用-CSDN博客 创建的应用&#xff0c;需要在主项目的myshop.settings.py 文件下注册 INSTALLED_APPS [django.contrib.admin,django.contrib.auth,django.contrib.contenttypes,django.contrib.sessions,django.contrib.messages,django.contrib.sta…

[DDR5 Jedec 4-1] 预充电命令 Precharge

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解DDR》 1. 预充电&#xff08;Precharge&#xff09;含义 由于SDRAM的寻址具体独占性&#xff0c;因此在进行完读写操作后&#xff0c;若需对同一L-Bank的另一行进行寻址&#xff0c;则必须先关闭原…

关于SQL中json类型字段优化查询

场景 写sql时&#xff0c;会出现大量的left join的情况&#xff0c;针对这种方式提供 两种解决方案。 解决方案 方案一 宽表&#xff0c;但是其维护性差 方案二 JSON类型字段 将业务查询的一些实体类 直接以JSON的形式存到数据库&#xff0c;以下是SQL代码查询的实例 dat…

vue3 源码下载地址

想要了解vue3底层的代码逻辑&#xff0c;就需要看其代码&#xff0c;为了技术的进步&#xff0c;冲啊。 源码下载地址&#xff1a; git clone https://github.com/vuejs/core.git 雄鹰每次折断翅膀&#xff0c;是为了飞的更高更远。技术提升起来&#xff0c;飞的更远更高。

Linux虚拟机设置定时任务(crontab)

Linux虚拟机设置定时任务(crontab) 在Linux中&#xff08;使用Cron&#xff09;&#xff1a; crontab 详解: crontab 是一个用于在 Unix 和类 Unix 操作系统上运行定期任务的工具。它允许用户根据特定的时间表执行命令或脚本&#xff0c;而无需手动执行它们。 使用 crontab…

0开篇-介绍

创作灵感 最近又开始写Python&#xff0c;换新机器了&#xff0c;加上回顾硬盘上的一些资料&#xff0c;发现当时用在态势上的一些机器学习内容一直没有收尾&#xff0c;2019年10月研发中心成立中断了机器学习产品的研发&#xff0c;加上后来疫情&#xff0c;这几年荒废了。有…

如何创建一个线程池,为什么不推荐使用Executors去创建呢?

我们在学线程的时候了解了几种创建线程的方式&#xff0c;比如继承Thread类&#xff0c;实现Runnable接口、Callable接口等&#xff0c;那对于线程池的使用&#xff0c;也需要去创建它&#xff0c;在这里我们提供2种构造线程池的方法&#xff1a; 方法一&#xff1a; 通过Thre…

【vue】vue2项目将npm包管理器修改为yarn包管理器

【vue】vue2项目将npm包管理器修改为yarn包管理器 1.删除node_modules文件夹、package-lock.json文件 2.全局安装yarn npm install -g yarn3.安装项目依赖 yarn install如果执行yarn install 报类似以下这种版本不兼容错误&#xff0c;执行 yarn config set ignore-engines …