前言
Go语言在多核并发上拥有原生的设计优势,Go语言从底层原生支持并发,无须第三方库、开发者的编程技巧和开发经验。
go是非常年轻的一门语言,它的主要目标是“兼具Python 等动态语言的开发速度和C/C 等编译型语言的性能与安全性”
go适合做什么
- 服务端开发
- 分布式系统,微服务
- 网络编程
- 区块链开发
- 内存KV数据库,例如boltDB、levelDB
- 云平台
推荐文档:http://www.topgoer.com/
安装GO环境
官方:https://golang.google.cn/
安装后查看
代码语言:javascript复制go version
成功显示
go version go1.16.3 windows/amd64
设置环境变量GOPROXY=https://goproxy.cn
创建WEB项目(iris)
仓库地址:https://github.com/kataras/iris/
创建
代码语言:javascript复制mkdir ZDevOpsGo
cd ZDevOpsGo
go mod init ZDevOpsGo
go get github.com/kataras/iris/v12@master
创建main.go
输入如下内容
代码语言:javascript复制package main
import "github.com/kataras/iris/v12"
func main() {
app := iris.Default()
app.Use(myMiddleware)
app.Handle("GET", "/", func(ctx iris.Context) {
ctx.JSON(iris.Map{"message": "hello world"})
})
// Listens and serves incoming http requests
// on http://localhost:8080.
app.Run(iris.Addr(":8080"))
}
func myMiddleware(ctx iris.Context) {
ctx.Application().Logger().Infof("Runs before %s", ctx.Path())
ctx.Next()
}
运行
代码语言:javascript复制go run main.go
或者编译后运行exe文件
代码语言:javascript复制go build
这样就可以访问
http://127.0.0.1:8080/
使用模板
代码语言:javascript复制package main
import "github.com/kataras/iris/v12"
func main() {
app := iris.New()
// Load all templates from the "./views" folder
// where extension is ".html" and parse them
// using the standard `html/template` package.
app.RegisterView(iris.HTML("./views", ".html"))
// Method: GET
// Resource: http://localhost:8080
app.Get("/", func(ctx iris.Context) {
// Bind: {{.message}} with "Hello world!"
ctx.ViewData("message", "Hello world!")
// Render template file: ./views/index.html
ctx.View("index.html")
})
// Method: GET
// Resource: http://localhost:8080/user/42
// 也可以使用正则表达式
// app.Get("/user/{id:string regexp(^[0-9] $)}")
app.Get("/user/{id:uint64}", func(ctx iris.Context) {
userID, _ := ctx.Params().GetUint64("id")
ctx.Writef("User ID: %d", userID)
})
// Start the server using a network address.
app.Run(iris.Addr(":8080"))
}
模板文件
views/index.html
代码语言:javascript复制<html>
<head>
<title>Hello Page</title>
</head>
<body>
<h1>{{ .message }}</h1>
</body>
</html>
运行就可以访问
http://localhost:8080 http://localhost:8080/user/42
使用配置文件
项目根目录创建iris.yml
FireMethodNotAllowed: true
DisableBodyConsumptionOnUnmarshal: true
TimeFormat: Mon, 01 Jan 2006 15:04:05 GMT
Charset: UTF-8
加载配置文件
代码语言:javascript复制// Start the server using a network address.
config := iris.WithConfiguration(iris.YAML("./iris.yml"))
app.Run(iris.Addr(":8080"), config)
JSON文件解析
代码语言:javascript复制package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
)
type Config struct {
Port int32
Project_name string
}
func readConfig() Config {
ExecPath, _ := os.Getwd()
filepath := path.Join(ExecPath, "config", "config.json")
data, err := ioutil.ReadFile(filepath)
fmt.Println("filepath:", filepath)
v := Config{}
if err != nil {
fmt.Println("读取配置文件失败", err)
return v
}
fmt.Println(string(data))
//读取的数据为json格式,需要进行解码
err = json.Unmarshal(data, &v)
if err != nil {
fmt.Println("解析json失败", err)
} else {
fmt.Println("port:", v.Port)
fmt.Println("Project_name:", v.Project_name)
}
return v
}
func main() {
readConfig()
}
对应的JSON文件
config/config.json
代码语言:javascript复制{
"port":8080,
"project_name":"码客说"
}
注意
JSON库在转换的时候会首字母大写,但是
project_name
这样的会解析为Project_name
, 而不是ProjectName
Sqlite
安装GCC环境
在Sourceforge官网,下载MinGW-W64 GCC-8.1
下载x86_64-win32-sjlj
解压后把类似于D:Toolsmingw64bin
添加到系统环境变量Path
里
添加后重启开发软件,后输入
代码语言:javascript复制go get github.com/mattn/go-sqlite3
示例
代码语言:javascript复制package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "./mydb.db")
checkErr(err)
//创建表
sql_table := `
CREATE TABLE IF NOT EXISTS userinfo(
uid INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(64) NULL,
departname VARCHAR(64) NULL,
created DATE NULL
);
`
db.Exec(sql_table)
//插入数据
stmt, err := db.Prepare("INSERT INTO userinfo(username, departname, created) values(?,?,?)")
checkErr(err)
res, err := stmt.Exec("小红", "研发部门", "2012-12-09")
checkErr(err)
id, err := res.LastInsertId()
checkErr(err)
fmt.Println("插入用户ID:", id)
//更新数据
stmt, err = db.Prepare("update userinfo set username=? where uid=?")
checkErr(err)
res, err = stmt.Exec("小明", id)
checkErr(err)
affect, err := res.RowsAffected()
checkErr(err)
fmt.Println("更新用户条数:", affect)
//查询数据
rows, err := db.Query("SELECT * FROM userinfo")
checkErr(err)
for rows.Next() {
var uid int
var username string
var department string
var created string
err = rows.Scan(&uid, &username, &department, &created)
checkErr(err)
fmt.Println("uid:", uid)
fmt.Println("username:", username)
fmt.Println("department:", department)
fmt.Println("created:", created)
}
//删除数据
stmt, err = db.Prepare("delete from userinfo where uid=?")
checkErr(err)
res, err = stmt.Exec(id)
checkErr(err)
affect, err = res.RowsAffected()
checkErr(err)
fmt.Println("删除条数:", affect)
db.Close()
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
注意
panic 会触发程序崩溃,正式上线不要用
Mysql
下载依赖
代码语言:javascript复制go get github.com/go-sql-driver/mysql
示例
代码语言:javascript复制package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB
func initDB() {
//"用户名:密码@[连接方式](主机名:端口号)/数据库名"
db, _ = sql.Open("mysql", "root:123456@(127.0.0.1:3306)/zdb") // 设置连接数据库的参数
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(5)
}
func main() {
initDB()
defer db.Close() //关闭数据库
err := db.Ping() //连接数据库
if err != nil {
fmt.Println("数据库连接失败")
return
}
//操作一:执行数据操作语句
sql := "insert into t_user (name) values ('berry')"
result, _ := db.Exec(sql) //执行SQL语句
n, _ := result.RowsAffected() //获取受影响的记录数
fmt.Println("受影响的记录数是", n)
//操作二:执行预处理
users := [2][]string{{"ketty"}, {"rose"}}
stmt, _ := db.Prepare("insert into t_user (name) values (?)") //获取预处理语句对象
for _, s := range users {
stmt.Exec(s[0]) //调用预处理语句
}
//操作三:单行查询
// var id, name string
// rows := db.QueryRow("select * from t_user where id=4") //获取一行数据
// rows.Scan(&id, &name)
// fmt.Println(id, "--", name)
//操作四:多行查询
rows, _ := db.Query("select * from t_user") //获取所有数据
var id, name string
for rows.Next() { //循环显示所有的数据
rows.Scan(&id, &name)
fmt.Println(id, "--", name)
}
rows.Close()
}
注意
defer 语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。
连接池的实现关键在于SetMaxOpenConns和SetMaxIdleConns,其中:
SetMaxOpenConns用于设置最大打开的连接数,默认值为0表示不限制。 SetMaxIdleConns用于设置闲置的连接数。
设置最大的连接数,可以避免并发太高导致连接mysql出现too many connections的错误。设置闲置的连接数则当开启的一个连接使用完成后可以放在池里等候下一次使用。
解析Nginx配置文件
代码语言:javascript复制package main
import (
"container/list"
"fmt"
"io/ioutil"
"os"
"path"
)
type Config struct {
name int32
value string
children list.List
}
func readConfig() Config {
ExecPath, _ := os.Getwd()
filepath := path.Join(ExecPath, "nginx", "test.psvmc.cn.conf")
data, err := ioutil.ReadFile(filepath)
fmt.Println("filepath:", filepath)
v := Config{}
if err != nil {
fmt.Println("读取配置文件失败", err)
return v
}
datastr := string(data)
level := 0
lastchar := ' '
for k, v := range datastr {
if v == '{' || v == '}' {
if v == lastchar {
if v == '{' {
level = 1
} else {
level -= 1
}
}
lastchar = v
fmt.Printf("%d %c level %dn", k, v, level)
}
}
// fmt.Println(datastr)
return v
}
func main() {
readConfig()
}
nginx配置
代码语言:javascript复制upstream test_psvmc_cn {
server 110.110.110.110:8080;
server 120.120.120.120:8080;
}
server {
#http
listen 80;
#https
listen 443;
server_name test.psvmc.cn;
client_max_body_size 200m;
ssl on;
ssl_certificate /etc/nginx/cert/xhkjedu.pem;
ssl_certificate_key /etc/nginx/cert/xhkjedu.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
#location
location / {
proxy_pass http://test_psvmc_cn/;
proxy_cookie_path / /;
proxy_redirect / /;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 200 m;
client_body_buffer_size 128k;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_buffer_size 64k;
proxy_buffers 8 64k;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 128k;
send_timeout 60;
}
}