二丫讲梵 二丫讲梵
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancker
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
推广
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • 网站状态 (opens new window)
    • json2go (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

二丫讲梵

行者常至,为者常成
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancker
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
推广
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • 网站状态 (opens new window)
    • json2go (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • Shell编程

  • Go编程笔记

    • 开发技巧

      • go日常开发代码片段
      • golang交叉编译
      • 两个切片内容相减的几种方法
      • golang以结构体中某个字段进行排序
      • vscode开发golang报黄提示composite literal uses unkeyed fields
      • golang使用$in或$nin查询MongoDB是否在数组内的数据
      • golang使用$push和$addToSet往数组添加字段的异同
      • MongoDB自增ID在golang中的实践
      • golang数据类型转换汇总
      • 记录VSCode中写Go代码切换Sqlite无CGO依赖版本的过程以及遇到的五个问题
        • 前言
        • 方案
        • 实践
        • 问题集锦
          • go 版本
          • mod 依赖的处理
          • IDE 的一个报错
          • golangci-lint 的问题
          • 关于前置 lint
    • 库包研究

    • 个人项目

  • 前端编程笔记

  • Go学习笔记

  • Vue-21年学习笔记

  • Vue-22年重学笔记

  • 编程世界
  • Go编程笔记
  • 开发技巧
二丫讲梵
2023-02-25
目录

记录VSCode中写Go代码切换Sqlite无CGO依赖版本的过程以及遇到的五个问题

这篇文章的发布时间较早,其中的内容可能已经过时,阅读时请注意甄别。

# 前言

我的 xirang (opens new window) 系统之前引入 sqlite 功能的时候,使用的驱动包是 github.com/mattn/go-sqlite3 v1.14.15,这个库现在在 go 项目当中,引用最多,应用最广,看项目 Used By 达到了 71k,俨然成为这一方面的标准,但有一个最大的问题就是,这是一个 C 语言实现的库,如果要应用这个库,那么你的环境就需要解决这个 CGO 依赖。

如果是在 CentOS 中运行,会看到如下报错:

[error] failed to initialize database, got error Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub
2023-02-24 12:30:41	PANIC	common/database.go:32	github.com/eryajf/go-ldap-admin/public/common.initSqlite3	failed to connect sqlite3: Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub
panic: failed to connect sqlite3: Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub
1
2
3

我的 Mac 没有遇到这个错误,但其他人 Windows 上也有遇到这个错误。

原本引入 sqlite 为了方便的,结果因为这个问题,反而变得麻烦起来,我看了一下 centos 上想要解决这个问题,要耗费相当一番功夫。

于是决定寻找一个相对优雅的解决方案。

# 方案

通过网上检索,我找到了一篇这样的文章:golang不使用cgo的sqlite驱动推荐 (opens new window),这篇文章的作者遇到的困境与我是一致的,他发现了一个无 CGO 版本的库 modernc.org/sqlite,因为这个库是在 gitlab,不太方便,于是作者给搬到了 github,但作者维护的并不及时,也不够规范(没有 go.mod 文件),我便没能应用起来。

后来又来到 gorm 的 issue 区寻找线索,发现了这个问题:Driver for pure Go sqlite implimentation (opens new window),其中一名开发者分享了他维护的一个库:glebarez/sqlite (opens new window),能够与 gorm 完美结合起来使用。

# 实践

说干就干,准备选用这个库来作为 sqlite 的 orm 驱动,具体代码文件内容可见:

点击查看
package common

import (
	"fmt"

	"github.com/eryajf/xirang/config"
	"github.com/eryajf/xirang/model"

	"github.com/glebarez/sqlite"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

// 全局数据库对象
var DB *gorm.DB

// 初始化数据库
func InitDB() {
	switch config.Conf.Database.Driver {
	case "mysql":
		DB = ConnMysql()
	case "sqlite3":
		DB = ConnSqlite()
	}
	dbAutoMigrate()
}

// 自动迁移表结构
func dbAutoMigrate() {
	_ = DB.AutoMigrate(
		&model.User{},
		&model.Role{},
		&model.Group{},
		&model.Menu{},
		&model.Api{},
		&model.OperationLog{},
	)
}

func ConnSqlite() *gorm.DB {
	db, err := gorm.Open(sqlite.Open(config.Conf.Database.Source), &gorm.Config{
		// 禁用外键(指定外键时不会在mysql创建真实的外键约束)
		DisableForeignKeyConstraintWhenMigrating: true,
	})
	if err != nil {
		Log.Panicf("failed to connect sqlite3: %v", err)
	}
	return db
}

func ConnMysql() *gorm.DB {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&collation=%s&%s",
		config.Conf.Mysql.Username,
		config.Conf.Mysql.Password,
		config.Conf.Mysql.Host,
		config.Conf.Mysql.Port,
		config.Conf.Mysql.Database,
		config.Conf.Mysql.Charset,
		config.Conf.Mysql.Collation,
		config.Conf.Mysql.Query,
	)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		// 禁用外键(指定外键时不会在mysql创建真实的外键约束)
		DisableForeignKeyConstraintWhenMigrating: true,
	})
	if err != nil {
		Log.Panicf("初始化mysql数据库异常: %v", err)
	}
	// 开启mysql日志
	if config.Conf.Mysql.LogMode {
		db.Debug()
	}
	Log.Infof("初始化mysql数据库完成! dsn: %s", showDsn)
	return db
}
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

在包引用的地方,直接把 "gorm.io/driver/sqlite" 改成 "github.com/glebarez/sqlite" 即可,但这只是完成了很小的一步,接下来遇到的问题才是大头。

# 问题集锦

# go 版本

因为依赖库对 go 版本支持在 1.18 以上,而我之前一直用的 1.17,这次看起来不得不升级一下版本了,于是将自己的 go 版本升级为 1.18.10。这个升级为后续的一个问题埋下伏笔,暂时按下不表,且看版本依赖处理时遇到的第一个问题。

# mod 依赖的处理

当我把编码搞定之后,准备直接运行 go mod tidy -v,但却发现各种过不去,这个时候我选择了两种方案来解决这个问题,思路重要,值得记录。

  • 方案一:把 mod 文件清空,然后重新 tidy,让依赖重新自检,但是这样子项目中其他的依赖也大多拉取了最新的版本,反而引出了更多的报错,这不是一个可取的方案。
  • 方案二:如果暂时不知道怎么写,那就先看看别人怎么写的,于是来到 "github.com/glebarez/sqlite" 依赖的 User By 页面,开始寻找能够借鉴学习的项目案例,经过一番查找,找到了: https://github.com/YPSI-SAS/Golang-GORM-tutoriel , 然后自己再把源码拉下来,按照自己的需求进行调配,配置完毕之后,tidy 检查一切没有问题。最后再把两个项目的 mod 文件进行比对,把 orm 相关的版本拷贝到主项目中,之后果然解决了问题。

有时候依赖的自检会受限于当前项目的各种版本,而且也并不能盲目升级,尤其是针对于生产的业务。

# IDE 的一个报错

当我把代码按照规划的方案编码之后,就看到了如下的报错,而且这个报错在好几个地方都出现。

错误信息如下:

实际程序编译以及运行都没有问题,这是因为依赖包大版本升级,但是 Vscode 还应用老的缓存导致,此时将当前窗口关闭,重新打开项目,即可看到这个报错消失。

# golangci-lint 的问题

一切搞定之后,我打算把代码合并到主分支,原以为经过几个小时的折腾,终于可以点下合并就休息了,结果却收到了 action 的 lint 检查失败,详见:action log (opens new window),我于是在本地开始调试 lint。

在本地调试的时候,却出现了如下错误,好吧,我似乎应该把 lint 放在提交代码之前,这是个需要优化的地方。

当我在本地运行 golangci-lint 的时候,看到了如下错误:

$ golangci-lint version
panic: load embedded ruleguard rules: rules/rules.go:13: can't load fmt

goroutine 1 [running]:
github.com/go-critic/go-critic/checkers.init.22()
	/Users/eryajf/software/go/pkg/mod/github.com/go-critic/go-critic@v0.6.3/checkers/embedded_rules.go:47 +0x52c
1
2
3
4
5
6

之后在 golangci-lint 仓库的 issue 区看到了一个说法: https://github.com/golangci/golangci-lint/issues/2374

如果 go 版本升级了,那么这个工具也需要升级,而且还不能一下子直接安装最新版本,因为当下用的 go 版本并不是最新版本的。这个时候来到 golangci-lint 的 release 页面,通过关键字进行搜索,找到支持 1.19 之前的那个版本,就安装这个版本的就可以。

执行如下命令进行安装:

$ go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.47.3
1

然后再来到本地跑 lint 发现就没有什么报错了。接着把 action (opens new window) 文件的 golang 版本以及插件版本都指定为对应合适的版本,再次运行检查就不会报错了。

# 关于前置 lint

我们使用 pre-commit (opens new window) 来完成这一功能。

安装:

$ pip3 install pre-commit
1

查看版本:

$ pre-commit --version
pre-commit 3.1.0
1
2

然后在项目根目录添加如下配置文件.pre-commit-config.yaml:

repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v3.1.0
    hooks:
    - id: check-yaml
    - id: trailing-whitespace
    - id: check-added-large-files
-   repo: https://github.com/golangci/golangci-lint # golangci-lint hook repo
    rev: v1.47.3 # golangci-lint hook repo revision
    hooks:
    - id: golangci-lint
      name: golangci-lint
      description: Fast linters runner for Go.
      entry: golangci-lint run --fix
      types: [go]
      language: golang
      pass_filenames: false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

然后运行如下命令将 hooks 载入到 git 配置文件中:

$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
1
2

然后将代码某处的 err 错误忽略不做处理,此时提交代码看看是否会检查:

$ gcmsg 'test pre check'
Check Yaml...............................................................Passed
Trim Trailing Whitespace.................................................Passed
Check for added large files..............................................Passed
golangci-lint............................................................Failed
- hook id: golangci-lint
- exit code: 1

config/config.go:30:11: ineffectual assignment to err (ineffassign)
        workDir, err := os.Getwd()
                 ^
1
2
3
4
5
6
7
8
9
10
11

如此就实现了一个简单的提交前的 lint 检查,这里只是先简单抛砖引玉,后续再深入研究一下pre-commit-hooks,是个很好很重要的东西。

微信 支付宝
上次更新: 2023/02/25, 11:44:10

← golang数据类型转换汇总 使用gorm进行联合查询的整理总结→

最近更新
01
go-cache包的使用简析
03-19
02
学习周刊-总第98期-2023年第11周
03-17
03
使用retry-go给项目添加重试机制
03-15
更多文章>
Theme by Vdoing | Copyright © 2017-2023 | 点击查看十年之约 | 浙ICP备18057030号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式