GoStudy

go笔记

配置go语言的编译环境

此处省略一万字

基础

首先变量的值用var定义,定义的类型和c一样的

  1. 声明
  • 第一种

    var name type
    name =value

这里和C不一样的就是C是 type name

  • 第二种

    var name =value

  • 第三种

    name :=value

    注意第三种会自动推变量的类型
    这种的好处就是可以不用写变量类型而直接赋值
    注意这种不能用于全局变量的声明!!!

    那么问题来了,”=”和”:=”有什么区别呢?希望各位好好思考一下

同时它也可以一次给多个赋值,和c一样

  • 第一种

    var name1,name2 type
    name1,name2 =value1,value2

  • 第二种

    var name1,name2 =value1,value2

  • 第三种

    name :=value

ps:定义了的必须要使用,不使用会报错,如果按ctrl+s,则vscode会自动给你把没使用的删掉
这条不仅仅是对变量名有效,对包名,函数什么的都有效

  1. 常量
    在定义的前面加个const就行了,和c一样

  2. 类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool   false
byte 和char一样
int
int16, uint16 -32768 ~ 32767, abs -> 0 ~ 65535
int32, uint32 -21亿~ 21亿, 0 ~ 42亿
int64, uint64
float32
float64
complex64
complex128
array 数组
struct 结构体
string
slice 切片
map
channel nil 通道
interface nil 接口
function nil 函数

对应的格式化打印占位符:

1
2
3
4
5
6
7
8
9
10
%v,根据你的类型输出
%T,打印变量类型
%s,打印字符串
%f,浮点类型
%x,%X,16进制 //%x:0-9,a-f %X:0-9,A-F
%c,打印字符
%p,打印地址
%d,10进制的整数
%b,2进制的整数
%o,8进制

  1. 算术运算符

    1. 和c一样
    • /

    • %

    • ++ 注意go里面没有++i

    • – 和上面一样

  2. 逻辑运算符

    • &&
    • ||
    • 上面的和c一样
  3. 位运算符

    X Y X&Y X|Y X^Y
    0 0 0 0 0
    0 1 0 1 1
    1 1 1 1 0
    1 0 0 1 1
  • &
  • |
  • ^
  • << 和 >>
  1. 赋值运算

    • =

    • +=

    • -=

    • *=

    • /=

    • %=

    • <<= 和 >>=

    • &=

    • ^=

    • |=

剩下的就没什么好讲的了 基本和c差不多

依赖管理

  • 依赖管理三要素
    • 配置文件,描述依赖 go.mod
    • 中心仓库管理依赖库 proxy
    • 本地工具 go get/mod

创建的命令为 go mod init projectname.go

依赖配置

依赖配置产生冲突的时候会选择最低的兼容版本

工具-go mod

  • init 初始化,创建go.mod文件
  • download 下载模块到本地缓存
  • tidy 增加需要的依赖,删除不需要的依赖

测试

首先测试很重要!!!!

单元测试–规则

  • 单元测试文件以 _test.go结尾

  • 测试函数为 func TestXxx(** testing.T)

  • 初始化函数逻辑放到TestMain中

单元测试–覆盖率

定义:代码覆盖是软件测试中的一种度量手段,是一种白盒测试方法,描述程序中源代码被测试的比例和程度,所得比例就称之为代码覆盖率。我们在做测试时,代码覆盖率常常被用来作为衡量测试好坏的指标。

我们必须尽可能的提高测试率。

  • 一般覆盖率:50%~60% 较高覆盖率:80%+
  • 测试分支相互独立,全面覆盖
  • 测试单元粒度足够小,函数单一职责

分层结构

  • 数据层:数据model
  • 逻辑层:业务entity
  • 视图层:试图view

并发编程

1.子协程

创建一个协程非常简单,就是在一个任务函数前面添加一个go关键字

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
package main

import (
"fmt"
"sync"
"time"
)

func hello(i int) {
fmt.Println("hello world: " + fmt.Sprint(i))
}

func test() {
// fmt.Println("开始咯")
for i := 0; i < 5; i++ {
go func(j int) { //开启协程
hello(j)
}(i)
}
time.Sleep(time.Second) //保证子协程在运行的时候主协程不退出
}

func main() {
test()
}

这里我们需要注意的是一定要加time.Sleep(time.Second),这是为了开启子协程的时候主协程不立刻退出(延迟两秒)

这里还有的就是他们会互相抢占资源,所以打印的不一定是按照顺序来的

比如这里我打印的就是

1
2
3
4
5
hello world: 1
hello world: 0
hello world: 3
hello world: 4
hello world: 2

2.通道

通道分为有缓冲无缓冲

  • 语法:

Unbuffered:=make(chan int) 整型无缓冲通道

buffered:=make(chan int ,10) 整形有缓冲通道

无缓冲通道用于执行同步通信,而有缓冲通道用于执行异步通信。

通道可以用这样的图来表示

将值发送到通道德代码块需要用<-运算符

  • 语法:
1
2
src:=make(chan string,5)//创建通道
src<- " hello"//通过通道发送字符串
1
data:=src //从通道接收字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

func main() {
src := make(chan int) //创建容量为1的通道
dest := make(chan int, 3) //创建容量为3的通道
go func() {
defer close(src) //关闭通道
for i := 0; i < 10; i++ {
src <- i //送到src里面
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
println(i)
}
}

通道的发送和接收特性

  1. 对于同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的。

  2. 发送操作和接收操作中对元素值的处理都是不可分割的。

  3. 发送操作在完全完成之前会被阻塞。接收操作也是如此。

3.WaitGroup同步

上面的第一个的代码不是很优雅,所以我们这里使用wait函数实行同步

代码如下:

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
package main

import (
"fmt"
"sync"
"time"
)
func hello(i int) {
fmt.Println("hello world: " + fmt.Sprint(i))
}

func ManyGoWait() {
var wg sync.WaitGroup
wg.Add(5) //计数器+5
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done() //计数器-1
hello(j)
}(i)
}
wg.Wait() //阻塞到计数器为0
}
func main() {
ManyGoWait()
}

4.runtime包

  • runtime.Gosched() 让出等待时间
  • runtime.Goexit() 退出当前协程
  • runtime.GOMAXPROCS(num int)设置最大核心数 如果改成1则只有一核执行

mutex

我们接下来先看这段代码

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
package main

import (
"fmt"
"sync"
)

var i int = 100
var wg sync.WaitGroup

func add() {
i += 1
fmt.Printf("i++: %v\n", i)
}

func sub() {
i -= 1
fmt.Printf("i--: %v\n", i)
}
func main() {
defer wg.Done()
for i := 0; i < 100; i++ {
wg.Add(1)
go add()
go sub()
}
fmt.Printf("end i: %v\n", i)
}

这里的运行的结果我们会发现有时候不是100,有时候是100。这就是因为异步的原因,那么我们怎么解决呢?

这里我们需要进行加锁

代码如下:

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
package main

import (
"fmt"
"sync"
"time"
)

var i int = 100
var wg sync.WaitGroup
var lock sync.Mutex//定义锁

func add() {
defer wg.Done()
lock.Lock() //上锁
i += 1
fmt.Printf("i++: %v\n", i)
time.Sleep(time.Millisecond * 10)
lock.Unlock() //解锁
}

func sub() {
lock.Lock() //上锁
defer wg.Done()
time.Sleep(time.Millisecond * 2)
i -= 1
fmt.Printf("i--: %v\n", i)
lock.Unlock() //解锁
}
func main() {

for i := 0; i < 100; i++ {
wg.Add(1)
go add()
go sub()
}
wg.Wait()
fmt.Printf("end i: %v\n", i)
}

timer

  • timer.c

代码如下:

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

package main

import (
"fmt"
"time"
)

func main() {
timer := time.NewTicker(time.Second * 2) //两秒
fmt.Printf("time.Now(): %v\n", time.Now())
t1 := <-timer.C//阻塞的时间,直到时间到了
fmt.Printf("t1: %v\n", t1)
}

两者的时间差了两秒

这里也可以不需要用t1接收 也就是说两者等价

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"fmt"
"time"
)

func main() {
timer := time.NewTicker(time.Second * 2) //两秒
fmt.Printf("time.Now(): %v\n", time.Now())
<-timer.C
fmt.Printf("time.Now(): %v\n", time.Now())
}
  • time.after()
1
2
3
4
5
6
7
8
9
10
11
12
package main
import (
"fmt"
"time"
)

func main() {
fmt.Printf("time.Now(): %v\n", time.Now())
<-time.After(time.Second * 2)
fmt.Printf("time.Now(): %v\n", time.Now())
}

上面都等价

  • time.Reset() 重置时间

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"fmt"
"time"
)

func main() {

timer := time.NewTicker(time.Second * 5) //原来是五秒
timer.Reset(time.Second * 1) //设置成为一秒
<-timer.C
fmt.Println("after")
}

ticker定时器

代码如下:

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

import (
"fmt"
"time"
)

func main() {
ticker := time.NewTicker(time.Second)//定时
counter := 1
for _ = range ticker.C {
fmt.Println("ticker...")
counter++
if counter > 5 {
break
}
}
}

每一秒运行一次,运行五次结束

原子变量

上面的那个还需要上锁,我们把代码改一下

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
package main

import (
"fmt"
"sync"
"sync/atomic"
"time"s
)

var i int32 = 100
var wg sync.WaitGroup
var lock sync.Mutex

func add() {
atomic.AddInt32(&i, 1)
}

func sub() {
atomic.AddInt32(&i, -1)
}
func main() {

for i := 0; i < 100; i++ {
// wg.Add(1)
go add()
go sub()
}
// wg.Wait()
time.Sleep(time.Second)
fmt.Printf("end i: %v\n", i)
}

标准库篇

创建文件

代码如下:会在当前目录下创建一个a.txt

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

import (
"fmt"
"os"
)

// 创建文件
func createFile() {
f, err := os.Create("a.txt")
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Println("f,name()", f.Name())
}
}
func main() {
createFile()
}

创建目录

代码如下:会在当前目录下创建一个a文件夹

1
2
3
4
5
6
7
// 创建目录
func makeDir() {
err := os.Mkdir("a", os.ModePerm)
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

如果想创建多级可以用以下的函数

1
2
3
4
5
6
7
func makeDir() {
//创建多级
err2 := os.MkdirAll("a/b/c", os.ModePerm)
if err2 != nil {
fmt.Printf("err2: %v\n", err2)
}
}

删除文件&目录

代码如下:

1
2
3
4
5
6
func remove() {
err := os.Remove("a.txt")
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

删除目录的代码如下:

1
2
3
4
5
6
func removeDir() {
err := os.RemoveAll("a")
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

删除a和a下面的所有的目录

打印当前工作目录

1
2
3
4
5
6
7
8
func wd() {
dir, err := os.Getwd()
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Printf("dir: %v\n", dir)
}
}

修改当前目录

1
2
3
4
5
6
7
func changeWd() {
err := os.Chdir("d:/")
if err != nil {
fmt.Printf("err: %v\n", err)
}
fmt.Println(os.Getwd())
}

修改当前目录到D盘

重命名

1
2
3
4
5
6
func Rename() {
err := os.Rename("test01.txt", "test02.txt")
if err != nil {
fmt.Printf("err: %v\n", err)
}
}

将test01.txt修改成为test02.txt

这里需要注意的是,我们假设test01.txt里面写的是111,而test02.txt里面的内容是222。执行上面的操作之后,原来的test02.txt将会被覆盖,也是是说test02.txt里面的内容将会变成111 这里需要大家注意一下

读文件

1
2
3
4
5
6
7
8
func readFile() {
b, err := os.ReadFile("test.txt")
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Printf("b: %v\n", string(b[:]))
}
}

写文件

1
2
3
4
5
// 写文件
func writeFile() {
s := "hello world"
os.WriteFile("test.txt", []byte(s), os.ModePerm)
}

但是这里需要注意的是这里会直接覆盖

打开文件

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

import (
"fmt"
"os"
)

func main() {
f, err := os.OpenFile("notes.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
// log.Fatal(err)
fmt.Printf("err: %v\n", err)
} else {
fmt.Printf("f: %v\n", f.Name())
}
if err := f.Close(); err != nil {
// log.Fatal(err)
}
}

读文件

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

func read() {
f, _ := os.Open("notes.txt")
for {
buf := make([]byte, 10)
n, err := f.Read(buf)
if err == io.EOF {
break
}
fmt.Printf("n: %v\n", n)
fmt.Printf("string(buf): %v\n", string(buf))
}

}

注意:这里可能会产生脏读

1
2
3
4
5
6
7
8
func read() {

f, _ := os.Open("a.txt")
buf := make([]byte, 3)//从第三个开始读
n, _ := f.ReadAt(buf, 4)//读四个
fmt.Printf("n: %v\n", n)
fmt.Printf("string(buf): %v\n", string(buf))
}

io包

NewReader()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"fmt"
"strings"
)

func main() {
r := strings.NewReader("hello world")//创建输入流
buf := make([]byte, 15)//创建通道
r.Read(buf)//输入到buf中
fmt.Printf("string(buf): %v\n", string(buf))
}

json包

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
package main

import (
"encoding/json"
"fmt"
)

type Person struct {
Name string
Age int
Email string
}
//结构体转json
func test() {
p := Person{
"tom",
20,
"666@email.com",
}
b, _ := json.Marshal(p)
fmt.Printf("string(b): %v\n", string(b))
}
//json转结构体
func test2() {
b := []byte(`{"Name":"tom","Age":20,"Email":"666@email.com"}`)
var p Person
json.Unmarshal(b, &p)
fmt.Printf("p: %v\n", p)
}

func main() {
// test()
test2()
}

xml包

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
package main

import (
"encoding/xml"
"fmt"
)

type Person struct {
Name string
Age int
Email string
}
//结构体转json
func test() {
p := Person{
"tom",
20,
"666.@email.com",
}
b, _ := xml.MarshalIndent(p, " ", " ")
fmt.Printf("string(b): %v\n", string(b))
}

func main() {
test()
}

结果:

1
2
3
4
5
6
string(b):  <Person>
<Name>tom</Name>
<Age>20</Age>
<Email>666.@email.com</Email>
</Person>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//json转结构体
func test1() {
s := `
string(b): <Person>
<Name>tom</Name>
<Age>20</Age>
<Email>666.@email.com</Email>
</Person>
`
b := []byte(s)
var p Person
xml.Unmarshal(b, &p)
fmt.Printf("p: %v\n", p)
}

结果:

1
p: {tom 20 666.@email.com}

mysql篇

安装驱动

go get -u github.com/go-sql-driver/mysql

初始化模块

go mod init m

执行 go mod tidy

go mod tidy

导入驱动

import (

“database/sql”

“fmt”

“time”

)

驱动代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"database/sql"
"fmt"
"time"
_ "github.com/go-sql-driver/mysql"
)

func main() {
d, err := sql.Open("mysql", "root:password@/go_db")
if err != nil {
panic(err)
}
fmt.Printf("d: %v\n", d)
//最大连接时长
d.SetConnMaxLifetime(time.Minute * 3)
//最大打开数
d.SetMaxOpenConns(10)
//空闲连接数
d.SetMaxIdleConns(10)
}

初始化

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
func initDB() (err error) {
dsn := "root:password@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True"
d, err := sql.Open("mysql", dsn)
if err != nil {
return err
}
err = d.Ping()
if err != nil {
return err
}
return nil
}

crud

插入

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
package main

import (
"database/sql"
"fmt"

_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

func initDB() (err error) {

dsn := "root:1234@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True"
d, err := sql.Open("mysql", dsn)
db = d
if err != nil {
return err
}
err = d.Ping()
if err != nil {
return err
}
return nil
}

func insert() {

s := "insert into user_tbl( username, password) values (?,?) "
r, err := db.Exec(s, "lisi", "ls123")
fmt.Println("走到这了")
if err != nil {
// fmt.Println("插入出现问题")
fmt.Printf("err: %v\n", err)
} else {
i, _ := r.LastInsertId()
fmt.Printf("i: %v\n", i)
}
}
func main() {
err := initDB()
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Println("初始化成功")
}
insert()
}

记录错误

1
2
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x20 pc=0x71d0f3]

代码如下:

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
package main

import (
"database/sql"
"fmt"

_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

func initDB() (err error) {

dsn := "root:1234@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True"
d, err := sql.Open("mysql", dsn)
// db = d
if err != nil {
return err
}
err = d.Ping()
if err != nil {
return err
}
return nil
}

func insert() {

s := "insert into user_tbl( username, password) values (?,?) "
r, err := db.Exec(s)
// db.Exec(s, "zhangsan", "zs123")
fmt.Println("走到这了")
if err != nil {
// fmt.Println("插入出现问题")
fmt.Printf("err: %v\n", err)
} else {
i, _ := r.LastInsertId()
fmt.Printf("i: %v\n", i)
}
}
func main() {
err := initDB()
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Println("初始化成功")
}
insert()
}

原因是因为db没有被赋值,也就是init的第三行,把它解掉注释就好了

查询

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

type User struct {
id int
username string
password string
}
//单行
func query() {
s := "select * from user_tbl where id=?"
var u User
err := db.QueryRow(s, 2).Scan(&u.id, &u.username, &u.password)
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Printf("u: %v\n", u)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//查询多行
func querymore() {
s := "select * from user_tbl"
r, err := db.Query(s)
var u User
defer r.Close()
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
for r.Next() {
r.Scan(&u.id, &u.username, &u.password)
fmt.Printf("u: %v\n", u)
}
}
}

更新

1
2
3
4
5
6
7
8
9
10
func update() {
s := "update user_tbl set username=?,password=? where id=?"
r, err := db.Exec(s, "big kite", "456789", 2)
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
i, _ := r.RowsAffected()
fmt.Printf("i: %v\n", i)
}
}

操作MongoDB

下载

下载地址

https://www.mongodb.com/download-center/community

打开客户端

mongo.exe

创建数据库

use go_db;

创建集合

db.createCollection(“student”);

下载驱动

go get go.mongodb.org/mongo-driver/mongo

插入文档

  1. 插入一条数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func insert() {
initDb()
s1 := Student{
Name: "tom",
Age: 20,
}
c := client.Database("go_db").Collection("Student")
ior, err := c.InsertOne(context.TODO(), s1)
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Printf("ior.InsertedID: %v\n", ior.InsertedID)
}
}
  1. 插入多条
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func insertMore() {
initDb()
c := client.Database("go_db").Collection("Student")
s1 := Student{
Name: "tom",
Age: 20,
}
s2 := Student{
Name: "rose",
Age: 20,
}
stus := []interface{}{s1, s2}
imr, err := c.InsertMany(context.TODO(), stus)
if err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Printf("imr.InsertedIDs: %v\n", imr.InsertedIDs)
}
}

到mongod里面查找数据是

db.Student.find()

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func find() {
initDb()
ctx := context.TODO()
defer client.Disconnect(context.TODO()) //关掉
c := client.Database("go_db").Collection("Student")

c2, err := c.Find(ctx, bson.D{})
if err != nil {
log.Fatal(err)
}
defer c2.Close(ctx)

for c2.Next(ctx) {
var res bson.D
c2.Decode(&res)
fmt.Printf("res: %v\n", res)
fmt.Printf("res.Map(): %v\n", res.Map())
}
}

更新

1
2
3
4
5
6
7
8
9
10
11
12
func update() {
initDb()
c := client.Database("go_db").Collection("Student")
ctx := context.TODO()
update := bson.D{{"$set", bson.D{{"name", "big kite"}, {"age", 22}}}}
ur, err := c.UpdateMany(ctx, bson.D{{"name", "rose"}}, update)
if err != nil {
log.Fatal(err)
}
fmt.Printf("ur.ModifiedCount: %v\n", ur.ModifiedCount)
}

删除

1
2
3
4
5
6
7
8
9
10
11

func delete() {
initDb()
c := client.Database("go_db").Collection("Student")
ctx := context.TODO()
dr, err := c.DeleteMany(ctx, bson.D{{"age", 20}})
if err != nil {
fmt.Printf("err: %v\n", err)
}
fmt.Printf("dr.DeletedCount: %v\n", dr.DeletedCount)
}

gorm

安装

go get -u gorm.io/gorm

go get -u gorm.io/driver/mysql

创建表

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
package main

import (
_ "github.com/go-sql-driver/mysql"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)

type Product struct {
gorm.Model
Code string
Price uint
}

func main() {
dsn := "root:runaway0926@tcp(127.0.0.1:3306)/golang_db?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}

//创建表
db.AutoMigrate(&Product{})
}

插入数据

1
2
3
4
5
6
7
8
func insert(db *gorm.DB) {
//插入数据
p := Product{
Code: "1001",
Price: 100,
}
db.Create(&p)
}

更新

1
2
3
4
5
6
7
func update(db *gorm.DB) {
var p Product
db.First(&p, 1)
db.Model(&p).Update("Price", 1000)
// db.Model(&p).Update(Product{Price: 1001, Code: "1002"}) //仅更新非零字段

}

查询

1
2
3
4
5
6
7
8
func find(db *gorm.DB) {
var p Product
db.First(&p, 1)
fmt.Printf("p: %v\n", p)
//db.First(&p, "code=?", "1001") //查找code字段为1001的记录
//fmt.Printf("p: %v\n", p)

}

删除

1
2
3
4
5
6
func delete(db *gorm.DB) {
//添加删除标记,不会真的删除
var p Product
db.First(&p, 1)
db.Delete(&p, 1)
}

声明模型

1
2
3
4
5
6
7
8
type Product struct {
gorm.Model //继承
Code string
Price uint

//注意这里要大写
}

注意

1
2
3
4
5
6
7
8
9
10
// 系统会自动帮忙调用
func init() {
dsn := "root:runaway0926@tcp(127.0.0.1:3306)/golang_db?charset=utf8mb4&parseTime=True&loc=Local"
d, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
db = d
}

1
2
3
4
5
6
7
8
9
10
11
//验证继承
func insert1() {
user := User{
Name: "tom",
Age: 20,
Brithday: time.Now(),
}
res := db.Create(&user)
fmt.Printf("res.RowsAffected: %v\n", res.RowsAffected)
fmt.Printf("user.ID: %v\n", user.ID)
}
1
2
3
4
5
6
7
8
9
10
11
//选择添加

var user = User{
Name: "tom",
Age: 20,
Brithday: time.Now(),
}

func insert2() {
db.Select("Name", "Age", "CreateAt").Create(&user)
}

批量添加

1
2
3
4
5
6
7
8
9
func insert3() {
var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
db.Create(&users)
}


注意这里需要修改sql_model
在my.ini
添加 sql_mode=NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO

gin

今天用vscode构建gin的时候

首先执行

接着上面显示下载好了

image-20230726164610717

但是开始写的时候,包含这个包爆红了那么我们怎么解决呢?

image-20230726164631786

步骤如下:

image-20230726165120119

  1. go env -w GOSUMDB=off
  2. go env -w GO111MODULE=on
  3. go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct

然后再输入

go get github.com/gin-gonic/gin

如下图所示

image-20230726165234693

然后再看我们的代码

image-20230726165339587

就不飘红啦

那么接下来,gin,启动!

image-20230726170328721

离谱,怎么跑不起来,仔细琢磨一番

会不会是端口被占用了?

查看端口占用

  1. win+r,cmd 老朋友了
  2. netstat -ano | findstr “8082”

如果输入上面的信息没有显示,说明有端口占用情况

image-20230726170948363

那么问题究竟是什么呢?

image-20230726170415381

少写了个: 我真谢谢你

那么继续,gin,启动!

image-20230726170515261

哎嘿,跑起来了,那么我们到8082端口看看

image-20230726170547244

芜湖,起飞