首页
壁纸
Search
1
go-canal 订阅和消费 binlog
1,370 阅读
2
Go语言精进之路-白明
448 阅读
3
Go语言精进之路-白明 | 变长参数函数的妙用
388 阅读
4
Clickhouse 实战记录
308 阅读
5
测试用
284 阅读
All
Golang
Python
Docker
Daily
ReadingMinutes
go语言精进之路
Database
登录
Search
标签搜索
go
database
binlog
multiprocessing
clickhouse
MrSnake
累计撰写
11
篇文章
累计收到
32
条评论
首页
栏目
All
Golang
Python
Docker
Daily
ReadingMinutes
go语言精进之路
Database
页面
壁纸
搜索到
11
篇与
MrSnake
的结果
Go语言精进之路-白明 | 变长参数函数的妙用
{mtitle title="目录"/}{lamp/}实现功能选项模式在日常Go编程中,我们经常会实现一些带有设置选项的创建型函数。对于一些复杂的Go包中的创建型函数,它要提供的可设置选项有时多达数十种,甚至后续还会增加。那么在选项增长的同时,依旧保持对外接口的稳定性,就成了关键。例:实现一个NewFinishedHouse函数,其中选项有:装修风格是否是中央空调地面材料墙面材料还有可能会增加的选项。版本1实现:使用结构体封装配置选项type FinishedHouse struct { style string isCentral bool floor string wall string } type Option struct { Style string IsCentral bool Floor string Wall string } func NewFinishedHouse(option *Option) *FinishedHouse { var ( style = "fashion" isCentral = true floor = "normal" wall = "standard" ) if option != nil { style = option.Style isCentral = option.IsCentral floor = option.Floor wall = option.Wall } return &FinishedHouse{ style: style, isCentral: isCentral, floor: floor, wall: wall, } }采用这种方式的好处是,当选项增加时,只需增加结构体option的字段,原本的函数签名是不变的。版本2实现:使用功能选项模式Go语言之父Rob Pike早在2014年就在其博文“自引用函数与选项设计”[2]中论述了一种被后人称为“功能选项”(functional option)的模式,这种模式应该是目前进行功能选项设计的最佳实践。type FinishedHouse struct { style string isCentral bool floor string wall string } type Option func(*FinishedHouse) func NewFinishedHouse(options ...Option) *FinishedHouse { h := &FinishedHouse{ style: "fashion", isCentral: true, floor: "normal", wall: "standard", } for _, option := range options { option(h) } return h } func WithStyle(style string) Option { return func(f *FinishedHouse) { f.style = style } } func WithIsCentral(isCentral bool) Option { return func(f *FinishedHouse) { f.isCentral = isCentral } } func WithFloor(floor string) Option { return func(f *FinishedHouse) { f.floor = floor } } func WithWall(wall string) Option { return func(f *FinishedHouse) { f.wall = wall } } func main() { fmt.Printf("%+v", NewFinishedHouse()) // 默认选项 fmt.Printf("%+v", NewFinishedHouse( WithStyle("classic"), WithIsCentral(false), )) }我们看到在该方案中,FinishedHouse的配置选项不是通过存储在结构体中的配置参数传入的,而是通过对FinishedHouse值本身进行操作的函数调用(利用函数的“一等公民”特质)实现的,并且通过使用变长参数函数,我们可以随意扩展传入的配置选项的个数。
2022年03月14日
388 阅读
6 评论
0 点赞
2022-03-03
Clickhouse 实战记录
{mtitle title="目录"/}{lamp/}查询订单中当前月之前没有出现过的顾客的数量即新顾客的数量思路:首先创建一张临时表,存放每个顾客首次购买的时间顾客表与这张临时表进行联表查询判断条件:新顾客,某一行的数据日期 = 首次购买日期老顾客,某一行的数据日期 > 首次购买日期全部顾客,某一行的数据日期 >= 首次购买日期其中,全部顾客 = 新顾客 + 老顾客mysql数据库映射到clickhouse一般来讲,业务数据都存放在 mysql 中,而要对业务数据做分析做分析的话,需要将 mysql 中的数据映射到 clickhouse,在进行分析。映射 mysql 数据库的方式,非常的方便,例如:-- 将 host 为 192.168.1.10:3306 mysql 的 oneline_pd 数据库 -- 通过用户 root 密码 123456 映射到 clickhouse 中,并命名为 online_pd create database online_pd engine = MySQL('192.168.1.10:3306', 'online_pd', 'root', '123456')先将数据入库到 ClickHouse 再进行查询需要注意的是,直接对映射过来的 mysql 中表进行查询的话是用不了索引的,会非常的满,需要先将数据 “load” 进 clickhouse 中存储引擎选择 MergeTree(),满足大部分需求。-- 如下,将 coupons 导入 clickhouse 中存储引擎 MergeTree() drop table if exists tmp_coupons; create table tmp_coupons engine = MergeTree() order by id as select * from online_pd.coupons;解决步骤1.首先创建一张临时表,存放每个顾客首次购买的时间-- 存着每个顾客的首次购买时间 drop table if exists tmp_customers_first_purchase_time; create table tmp_customers_first_purchase_time( `username` String, `first_purchase_time` Date, ) engine = MergeTree order by username; -- 插入数据 -- tmp_customer_month_buy 顾客的每个月消费情况 insert into tmp_customers_first_purchase_time select username min(buy_time) AS first_purchase_time from tmp_customer_month_buy group by username2.顾客表与这张临时表进行联表查询,并进行判断得出结果-- 创建存放新老顾客的表 drop table if exists tmp_customers_new_old; create table tmp_customers_new_old( `username` String comment '用户名', `date` Date comment '购买月份', `new_customer` Int32 comment '新客户数', `old_customer` Int32 comment '老客户数', `all_customer` Int32 comment '全部客户' ) engine = MergeTree order by (shop_no, date); -- 进行判断插入数据 INSERT INTO tmp_customers_new_old SELECT mb1.name AS name, mb1.date AS date, -- 购买月份 = 首次购买日期 新顾客 countIf(Distinct mb1.customer_no, created_at = date) as new_customers, -- 购买月份 < 首次购买日期 老顾客 countIf(Distinct mb1.customer_no, created_at < date) as old_customers, -- 购买月份 <= 首次购买日期 全部顾客 = 新顾客 + 老顾客 countIf(Distinct mb1.customer_no, created_at <= date) as all_customers FROM tmp_customer_month_buy as mb1 join tmp_customers_first_purchase_time as mb2 on mb1.username = mb2.username group by mb1.name,利用 clickhouse 内置函数进行 aes-256-cbc 加密-- 语法 encrypt('mode', 'plaintext', 'key' [, iv, aad])iv 初始化向量add 额外的身份验证数据加密-- 输入16位偏移量 select encrypt('aes-256-cbc', 'mrsnake', '12345678910121314151617181920212', '1234567891012131')
2022年03月03日
308 阅读
3 评论
0 点赞
Go语言精进之路-白明
代码块是代码执行流流转的基本单元,代码执行流总是从一个代码块跳到另一个代码块。 Go语言中分为两类代码块,一类为由代码中直观可见通过大括号包括的**显示代码块**,另一类则是没有大括号包裹的**隐式代码块**。**隐式代码块又分成:**
2022年02月21日
448 阅读
2 评论
1 点赞
2022-02-14
Docker 小记
Docker-compose 两个容器之间通信配置另一个容器的网卡,并与之进行通信以我自己的 Clickhouse 为例,想要与已经部署的 mysql 服务配置在同一网卡下。1.首先找到创建 mysql 服务生成的网卡mac@mrsnake ~ % docker network ls NETWORK ID NAME DRIVER SCOPE 1de739ed1402 bridge bridge local d72795b661b2 host host local 7439b4407605 slave_mysql57_default bridge local发现名为 slave_mysql57_default 的网卡2.写 docker-compose 文件// 与 service 同级 networks: extnetwork: external: name: "slave_mysql57_default"3.实际调用,完整示例version: "3" services: ch_server: image: yandex/clickhouse-server ports: - "8123:8123" - "9000:9000" - "9009:9009" networks: extnetwork: // 自定义的名称 ipv4_address: 172.23.0.3// 设置ip地址 ulimits: nproc: 65535 nofile: soft: 262144 hard: 262144 ch_client: image: yandex/clickhouse-client entrypoint: - /bin/sleep command: - infinity networks: extnetwork: // 自定义名称 external: // 使用外部已经定义好的名字 name: "slave_mysql57_default"查看 slave_mysql57_default 的网卡的 ip 信息boohee@mrsnake ~ % docker inspect slave_mysql57_default | grep IPv4 -B 3 "Name": "mysql5.7_slave", "EndpointID": "b5ff422fc00578", "MacAddress": "02:42:ac:17:00:02", "IPv4Address": "172.23.0.2/16",4.启动docker-compose up -d
2022年02月14日
157 阅读
2 评论
9 点赞
2022-01-28
Golang | 常用包整合
reflect、time.Time、strconv
2022年01月28日
181 阅读
2 评论
1 点赞
1
2
3