day2 go的高级用法 + 使用gin与sqlx进行页面与数据库的交互

75 阅读4分钟

并发编程

在每次迭代中,我们使用关键字go创建一个新的并发goroutine。这意味着每个goroutine都可以并行地执行。

在每个goroutine中,我们定义了一个匿名函数,该函数接受一个整数参数num。在函数体中,我们调用了之前定义的print函数,并将当前迭代的整数作为参数传递给它。这样,每个goroutine都会打印不同的数字。

为了确保所有goroutine都有足够的时间执行,我们使用time.Sleep函数将程序暂停了一秒钟。

总结起来,这段代码创建了一组并发的goroutine,每个goroutine都会调用print函数打印一个数字。通过使用goroutine和睡眠函数,我们可以确保这些goroutine有足够的时间来执行,并且它们的输出可能是交织在一起的。

package main

import (
	"fmt"
	"time"
)

func print(num int) {
	fmt.Println("this is " + fmt.Sprint(num))
}

func main() {
	for i := 0; i < 5; i++ {
		go func(num int) {
			print(num)
		}(i)
	}
	time.Sleep(time.Second)
}

首先,在main函数中创建了两个通道,srcdest,分别用于发送和接收整数。其中,src通道没有指定缓冲区大小(即无缓冲通道),而dest通道指定了缓冲区大小为3。

接下来,通过go关键字创建了两个匿名函数的goroutine。

第一个goroutine中的匿名函数使用defer关键字来确保在函数结束时关闭src通道。然后,它使用一个循环将数字1到8发送到src通道。

第二个goroutine中的匿名函数使用defer关键字来确保在函数结束时关闭dest通道。然后,它使用range关键字从src通道中接收数据,并将接收到的每个数字的平方发送到dest通道。

最后,在主goroutine中使用range关键字从dest通道中接收数据,并将每个接收到的数字打印出来。

总结一下程序的执行流程:

  1. 创建了两个通道srcdest
  2. 创建第一个goroutine,在其中将数字1到8发送到src通道。
  3. 创建第二个goroutine,在其中从src通道接收数据并将其平方后发送到dest通道。
  4. 主goroutine从dest通道中接收数据并打印出来。
package main

// 通过通道来实现共享内存

func main() {
	src := make(chan int)
	dest := make(chan int, 3)

	go func() {
		defer close(src)
		for i := 1; i < 9; i++ {
			src <- i
		}
	}()

	go func() {
		defer close(dest)
		for i := range src {
			dest <- i * i
		}
	}()

	for i := range dest {
		println(i)
	}
}

main函数内部,我们声明了一个WaitGroup类型的变量wg,它用于等待协程的完成。

然后,我们调用Add方法将wg的计数器增加到2。这是因为后面我们会启动两个协程,所以我们设置计数器为2,以便在这两个协程完成后,程序可以继续执行。

接下来,我们使用一个for循环来启动两个协程。循环变量i的初始值为1,每次循环增加1,直到i的值大于等于3时停止循环。

在循环体内部,我们使用go关键字启动一个匿名的函数作为协程。这个匿名函数接受一个num参数,它表示当前循环的迭代值i

在匿名函数内部,我们使用defer关键字来延迟执行wg.Done()方法,这样无论协程是否正常结束,都会调用wg.Done()来减少wg的计数器。

然后,我们调用println函数,打印num的值。

在匿名函数的定义之后,我们立即调用它,并传递当前循环的迭代值i作为参数。

最后,我们调用wg.Wait()方法,这会阻塞程序的执行,直到wg的计数器变为0,即所有协程都完成了。

// 计数器

package main

import "sync"

func main() {
	var wg sync.WaitGroup

	wg.Add(2)
	for i := 1; i < 3; i++ {
		go func(num int) {
			defer wg.Done()
			println(num)
		}(i)
	}
	wg.Wait()
}

使用gin与sqlx进行页面与数据库的交互

  1. 引入必要的包,包括Gin、MySQL驱动和sqlx。2. 定义了一个Person结构体,表示数据库中的一条person记录。3. 初始化mysql数据库连接,使用sqlx包。4. 定义了返回JSON数据的统一格式pageInfo。5. 使用Gin定义几个示例路由:
    - "/":简单返回字符串
    - "/test1/:name":获取path参数
    - "/test2":获取query参数
    - "/sqlTest":从mysql查询数据并返回6. 主函数启动Gin服务,监听8000端口。7. sqlTest接口展示了如何使用sqlx从mysql获取数据,并封装返回。
package main

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

type Person struct {
	UserId   int    `db:"user_id"`
	Username string `db:"username"`
	Sex      string `db:"sex"`
	Email    string `db:"email"`
}

var DB *sqlx.DB

func initDB() {
	database, error := sqlx.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/gotest")

	if error != nil {
		fmt.Println("fail to connect")
		return
	}

	DB = database
}

type pageInfo struct {
	Code int         `json:"code"`
	Data interface{} `json:"data"`
}

func main() {

	// 连接mysql
	initDB()

	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "hello word")
	})

	// 获取api参数
	r.GET("/test1/:name", func(ctx *gin.Context) {
		name := ctx.Param("name")

		ctx.String(http.StatusOK, "hello"+name)
	})

	// 获取url参数
	r.GET("/test2", func(ctx *gin.Context) {
		name := ctx.DefaultQuery("name", "默认")

		ctx.String(http.StatusOK, "hello"+name)
	})

	r.GET("/sqlTest", func(ctx *gin.Context) {
		var person []Person
		id := ctx.DefaultQuery("id", "1")
		DB.Select(&person, "select * from person where user_id = ?", id)
		ctx.JSON(200, pageInfo{
			Code: 200,
			Data: person,
		})
	})
	//监听端口默认为8080
	r.Run(":8000")
}