0%

vim 常用快捷键

vim快捷键

《Linux私房菜基础学习篇》Page278-280

阅读全文 »

MacOS 使用技巧

VIM常用快捷键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ 
// 光标移动到最后一个字符

0
// 光标移动到首位

ZZ
// 保存退出

dt<character>
// 删除到该字符

f<character>
// 将光标移动到,从光标当前位置开始第一个该字符的位置

阅读全文 »

gin-swagger 的使用

Swagger中文文档

准备工作

引入swaggo依赖:

1
2
3
4
5
6
7
## swagger 依赖/也可以通过先import,再运行go mod tidy下载gin-swagger
go get -u "github.com/swaggo/files"
go get -u "github.com/swaggo/gin-swagger"

## swagger 命令行工具
go get -u github.com/swaggo/swag/cmd/swag
go install github.com/swaggo/swag/cmd/swag@latest

项目地址:gin-swagger项目地址

阅读全文 »

摆脱未知

lo:golang版lodash

lodash,web前端领域的“瑞士军刀”。自从上手golang以来,寻找了4年多类似lodash的golang实现,终于因为golang1.18泛型的支持,得以如愿。目前已在日志同步服务中有所应用(Chunk)。
https://github.com/samber/lo

GitHub Copilot

担心被端掉饭碗?那不如来拥抱变化。github联合openAI建立的代码模型,把你从枯燥的编码中解放出来,目前已支持 Python、JavaScript、TypeScript、Ruby 和 Go 等主流语言。
当前为技术预览版,需要官网申请许可,绑定许可到编辑器中,支持Visual Studio Code和JetBrains旗下编辑器,具体操作方式详见github文档。
https://copilot.github.com/

Error lens

一个VsCode插件 可以帮助你快速定位到代码错误

阅读全文 »

ClickHouse 优缺点及性能情况

「优点」

  1. 为了高效的使用CPU,数据不仅仅按列存储,同时还按向量进行处理;
  2. 数据压缩空间大,减少IO;处理单查询高吞吐量每台服务器每秒最多数十亿行;
  3. 索引非B树结构,不需要满足最左原则;只要过滤条件在索引列中包含即可;即使在使用的数据不在索引中,由于各种并行处理机制 ClickHouse 全表扫描的速度也很快;
  4. 写入速度非常快,50-200M/s,对于大量的数据更新非常适用。

「缺点」

  1. 不支持事务,不支持真正的删除/更新;
  2. 不支持高并发,官方建议qps为100,可以通过修改配置文件增加连接数,但是在服务器足够好的情况下;
  3. SQL满足日常使用80%以上的语法,join写法比较特殊;最新版已支持类似SQL的join,但性能不好;
  4. 尽量做1000条以上批量的写入,避免逐行insert或小批量的insert,update,delete操作,因为ClickHouse底层会不断的做异步的数据合并,会影响查询性能,这个在做实时数据写入的时候要尽量避开;
  5. Clickhouse快是因为采用了并行处理机制,即使一个查询,也会用服务器一半的CPU去执行,所以ClickHouse不能支持高并发的使用场景,默认单查询使用CPU核数为服务器核数的一半,安装时会自动识别服务器核数,可以通过配置文件修改该参数。
阅读全文 »

关于路由层及逻辑层框架设计的思考

背景

当前服务端的设计逻辑按照三层主体架构方式实现:路由层-逻辑层-数据层,在路由层和逻辑层数据交互方式和代码冗余性方面与团队人员出现了分歧,引发了一些思考。

「架构简介」

  1. 路由层:路由层承担参数校验,身份验证及解析,路由实体返回功能,有对 gin.context 操作权限;
  2. 逻辑层:实现主体复杂业务逻辑,构建路由返回实体,无 gin.context 和数据库连接的操作权限;
  3. 数据层:实现底层数据获取,操作数据库,根据封装性和实用性操作部分简单业务逻辑,有数据库连接的操作权限;
  4. 逻辑层和数据库层应提供 interface 以实现目录功能,所有对外暴露的函数及功能均应在 interface 中体现,并在 interface 中尽可能的提供具体的参数及返回类型。
阅读全文 »

PostgreSQL 用法总结

  • 实现 upsert
1
2
3
4
5
6
7
8
9
-- 使用ON conflict (  )  DO子句
-- 下面的意思即为当 'user_id' 重复时,执行 UPDATE 操作
-- 当 'user_id' 不重复时,执行 INSERT 操作
INSERT INTO tb_user_info ( user_id, sex, "password" )
VALUES
( 1, '女', 'kissssss' ) ON conflict ( user_id) DO
UPDATE
SET sex = '女',
"password" = 'kissssss';
  • CREATE SCHEMA 时名称缺省使用 user_name ,且不能以 pg_ 开头。
  • DROP SCHEMA 时添加 CASCADE 参数,自动删除该模式下数据库对象。对应的,添加 RESTRICT 参数,如果该模式下还存在数据库对象,则不允许删除该模式,RESTRICT 为缺省值。
  • TRUNCATE TABLE xxx RESTART IDENTITY;:重置自增主键为 1 。
阅读全文 »

Go 实现上传下载功能

上传

单文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

func main() {
router := gin.Default()
// 给表单限制上传大小 (默认 32 MiB)
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// 单文件
file, _ := c.FormFile("file")
log.Println(file.Filename)

// 上传文件到指定的路径
c.SaveUploadedFile(file, "./test.xmind")

c.String(http.StatusOK, fmt.Sprintf("uploaded!"))
})
router.Run(":8080")
}

阅读全文 »

翻转字符串

以字符串中间字符为中心,遍历交换前后字符来达到翻转的目的

因为中英文字符所占用byte的长度不一致,一个中文字符在utf-8编码集中占用3个字节,导致len()会出现问题,故使用如下方法:

1
2
3
4
5
6
7
8

str := "hello世界"
// 方法一
strArr := []rune(str)
fmt.Println(len(strArr))
// 方法二
fmt.Println(utf8.RuneCountInString(str)) // 调用 unicode/utf8 标准库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package main

import "fmt"

func ReverseString(str string) string {
strArr := []rune(str)
for i := 0; i < len(strArr)/2; i++ {
strArr[len(strArr)-1-i], strArr[i] = strArr[i], strArr[len(strArr)-1-i]
}
return string(strArr)
}

func main() {
str := "hello世界"
fmt.Println(ReverseString(str))
}

阅读全文 »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

func main() {
f, err := excelize.OpenFile("./HealthCheck.xlsx")
if err != nil {
fmt.Println(err)
return
}
defer func() {
// Close the spreadsheet.
if err := f.Close(); err != nil {
fmt.Println("Excel 文件关闭失败: " + err.Error())
}
}()

// Get all the rows in the Sheet1.
rows, err := f.GetRows("监测点列表")
if err != nil || len(rows) == 0 {
fmt.Println("Excel 文件读取失败: " + err.Error())
return
}

for _, row := range rows[1:] {
// 在表格末尾有空格的时候,每一行实际的 row 并不等长
// 但是行首有空格并不会导致 row 长度变短
rowTmp := make([]string, 6)
for k, v := range row {
rowTmp[k] = v
}
fmt.Printf("%#v\n", row)
fmt.Printf("%#v\n", rowTmp)
}

fmt.Println("----------------------------")

r, _ := f.Rows("监测点列表")
for {
if r.Next() {
rst, _ := r.Columns()
fmt.Printf("%#v\n", rst)
} else {
break
}
}

fmt.Println("----------------------------")

// 检查行的存在性
visible1, _ := f.GetRowVisible("Sheet1", 2)
visible2, _ := f.GetRowVisible("代理列表", 2)
visible3, _ := f.GetRowVisible("代理列表", 10)
fmt.Println(visible1, visible2, visible3)

fmt.Println("----------------------------")
}

阅读全文 »