go语言中,从1.11开始,引入module,进行版本管理。
通过使用module,工程目录的位置不用必须放在GOPATH下。
本文介绍 module的使用。
下文中用的Go版本是1.13。
1. go mod命令
通过go mod可以进行modules的相关操作。
首先看下 go mod命令:
$ go help mod
Go mod provides access to operations on modules.
Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.
Usage:
go mod <command> [arguments]
The commands are:
download download modules to local cache // 下载依赖的module到本地cache
edit edit go.mod from tools or scripts
graph print module requirement graph
init initialize new module in current directory // 在当前目录下初始化新的module
tidy add missing and remove unused modules // 添加缺失的module,移出不用的module
vendor make vendored copy of dependencies // 将依赖复制到vendor下
verify verify dependencies have expected content
why explain why packages or modules are needed
Use "go help mod <command>" for more information about a command.
2.使用module举例
2.1 定义module
在任意目录下创建工程目录,可以不是GOPATH路径下。
$ mkdir hello_mysql
$ pwd
/home/lanyang/workspace/go_example/hello_mysql
$ go mod init hello_mysql
go: creating new go.mod: module hello_mysql
$ ll
-rw-rw-r--. 1 lanyang lanyang 28 Dec 21 18:25 go.mod
$ cat go.mod
module hello_mysql
go 1.13
新建源码文件 main.go
, 内容如下:
// main.go
package main
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
var DB *sql.DB
var dataBase = "root:Aa123456@tcp(192.168.0.101:3306)/?timeout=5s&readTimeout=6s"
func mysqlInit() {
var err error
DB, err = sql.Open("mysql", dataBase)
if err != nil {
log.Fatalln("open db fail:", err)
}
}
func main() {
mysqlInit()
execSql()
}
func execSql() {
var value int
err := DB.QueryRow("select 1").Scan(&value)
if err != nil {
log.Println("query failed:", err)
return
}
log.Println("value:", value)
}
以上代码实现连接MySQL服务器,执行简单的SQL语句。
2.2 编译
$ go build
go: downloading github.com/go-sql-driver/mysql v1.4.1
go: extracting github.com/go-sql-driver/mysql v1.4.1
go: finding github.com/go-sql-driver/mysql v1.4.1
$ ll
total 5788
-rw-rw-r--. 1 lanyang lanyang 75 Dec 22 16:57 go.mod
-rw-rw-r--. 1 lanyang lanyang 179 Dec 22 16:57 go.sum
-rwxrwxr-x. 1 lanyang lanyang 5912033 Dec 22 16:58 hello_mysql
-rw-rw-r--. 1 lanyang lanyang 669 Dec 22 16:57 main.go
在Go 1.13中,继续使用临时环境变量GO111MODULE来设置是否使用module。
GO111MODULE 可设置为off, on, 或auto (默认)。
如果 GO111MODULE=auto 或没有设置, go command(即go build, go test go get等)是否使用module取决于是否存在go.mod文件。
如果当前目录,或父目录中存在go.mod文件,那么go command就会使用module,否则不会使用module。
例子中,通过定义module,已经创建了go.mod
文件,这样,执行go command的时候,就会使用module 查找和下载依赖包,并将依赖包信息添加到go.mod
文件中。
下载的依赖包放在$GOPATH/pkg/mod
。
$ ll $GOPATH/pkg/mod/
total 8
drwxrwxr-x. 3 lanyang lanyang 4096 Dec 22 16:58 cache
drwxrwxr-x. 3 lanyang lanyang 4096 Dec 22 16:58 github.com
go.mod
文件内容被修改为:
module hello_mysql
go 1.13
require github.com/go-sql-driver/mysql v1.4.1
编译后,创建可执行文件hello_mysql
,执行:
$ ./hello_mysql
2019/12/22 17:19:19 value: 1
3.module 与 vendor
为了兼容老版本,或者想把所有的依赖包放在一个目录下,可以使用go mod vendor
。
go mod vendor
会在根目录下创建 vendor
目录,里面存放所有的依赖包。
编译的时候,加上选项-mod=vendor
,就可以使用vendor
目录下的依赖包。
继续使用上面的例子。
清理pkg/mod:
$ rm -rf $GOPATH/pkd/mod
例子代码目录下,只保留go.mod
和main.go
。
使用vendor存放依赖包,执行go mod vendor
:
$ go mod vendor
go: downloading github.com/go-sql-driver/mysql v1.4.1
go: extracting github.com/go-sql-driver/mysql v1.4.1
go: finding google.golang.org/appengine v1.6.5
go: downloading google.golang.org/appengine v1.6.5
go: extracting google.golang.org/appengine v1.6.5
$ ll
total 16
-rw-rw-r--. 1 lanyang lanyang 128 Dec 22 17:23 go.mod
-rw-rw-r--. 1 lanyang lanyang 1034 Dec 22 17:23 go.sum
-rw-rw-r--. 1 lanyang lanyang 669 Dec 22 17:19 main.go
drwxrwxr-x. 4 lanyang lanyang 4096 Dec 22 17:23 vendor
vendor
目录以及go.sum
文件被创建。
查看go.mod
文件,内容被修改为:
module hello_mysql
go 1.13
require (
github.com/go-sql-driver/mysql v1.4.1
google.golang.org/appengine v1.6.5 // indirect
)
查看下vendor
目录的内容:
$ ll vendor/
total 12
drwxrwxr-x. 3 lanyang lanyang 4096 Dec 22 17:23 github.com
drwxrwxr-x. 3 lanyang lanyang 4096 Dec 22 17:23 google.golang.org
-rw-rw-r--. 1 lanyang lanyang 145 Dec 22 17:23 modules.txt
可以看到目录下存放着所有的依赖包。
编译时,添加-mod=vendor
:
$ go build -mod=vendor
$ ll
total 5792
-rw-rw-r--. 1 lanyang lanyang 128 Dec 22 17:23 go.mod
-rw-rw-r--. 1 lanyang lanyang 1034 Dec 22 17:23 go.sum
-rwxrwxr-x. 1 lanyang lanyang 5912033 Dec 22 17:34 hello_mysql
-rw-rw-r--. 1 lanyang lanyang 669 Dec 22 17:19 main.go
drwxrwxr-x. 4 lanyang lanyang 4096 Dec 22 17:23 vendor
此时,就会在vendor中查找依赖包。
执行:
$ ./hello_mysql
2019/12/22 17:36:40 value: 1
这种方式中,既使用了module特性,摆脱了工程目录对GOPATH的依赖,又使用了vendor存放依赖包。
尤其是在上线前的编译和打包阶段,提前在vendor目录存放依赖包,就可以不用再通过网络去下载,避免了网络不稳定的影响,从而可以节省大量的时间。