Gin 基礎 :
Gin 的hello world :

package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { engine := gin.Default() engine.GET("/", func(context *gin.Context) { context.String(http.StatusOK,"hello world!") }) engine.Run() }
Gin 的 context.Params(path 參數) :

package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) func main() { engine := gin.Default() engine.GET("/:name/*rest", func(context *gin.Context) { context.String(http.StatusOK,"hello world!") fmt.Println(context.Params) params := context.Params fmt.Printf("%T\n", params) ret,ok := params.Get("name") if ok{ fmt.Println(ret) } fmt.Println(params[0]) }) engine.Run() }
Gin 的 context.Query (get 參數):

package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) func main() { engine := gin.Default() engine.GET("/", func(context *gin.Context) { context.String(http.StatusOK,"hello world!") fmt.Println(context.Query("name")) // 如果不存在返回 空串 fmt.Println(context.DefaultQuery("name","none"))// 如果不存在返回 none }) engine.Run() }
Gin 的 context.PostForm(post 參數):

package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) func main() { engine := gin.Default() engine.POST("/", func(context *gin.Context) { context.String(http.StatusOK,"hello world") fmt.Println(context.PostForm("name")) fmt.Println(context.DefaultPostForm("name","none")) }) engine.Run() }
Gin 的HTML渲染:

package main import ( "github.com/gin-gonic/gin" "html/template" "net/http" ) func main() { eng := gin.Default() eng.SetFuncMap(template.FuncMap{ "safe": func(s string)template.HTML { return template.HTML(s) }, }) eng.LoadHTMLGlob("templates/**/*") eng.GET("/test01", func(context *gin.Context) { context.HTML(http.StatusOK,"test/test01.html",gin.H{ "a":`<a href="http://www.baidu.com">百度一下</a>`, }) }) eng.Run() }

{{define "test/test01.html"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>posts/index</title> </head> <body> <h3>hello test01</h3> {{ .a | safe }} </body> </html> {{end}}
注意:使用自定義模板函數的時候要先 SetFuncMap 后 LoadHTMLGlob
當HTML文件中引用了靜態文件時:

package main import ( "github.com/gin-gonic/gin" "html/template" "net/http" ) func main() { eng := gin.Default() eng.SetFuncMap(template.FuncMap{ "safe": func(s string)template.HTML { return template.HTML(s) }, }) eng.Static("/xxx","./static") eng.LoadHTMLGlob("templates/**/*") eng.GET("/test01", func(context *gin.Context) { context.HTML(http.StatusOK,"test/test01.html",gin.H{ "a":`<a href="http://www.baidu.com">百度一下</a>`, }) }) eng.Run() }

{{define "test/test01.html"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>posts/index</title> </head> <body> <h3>hello test01</h3> {{ .a | safe }} <script src="xxx/js/my.js"></script> <script> printHello() </script> </body> </html> {{end}}

function printHello() {
console.log("hello world!")
}
Gin 的文件上傳:
單個文件上傳:

<!DOCTYPE html> <html lang="zh-CN"> <head> <title>上傳文件示例</title> </head> <body> <form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data"> <input type="file" name="f1"> <input type="submit" value="上傳"> </form> </body> </html>

package main import ( "fmt" "github.com/gin-gonic/gin" "log" "net/http" ) func main() { eng :=gin.Default() eng.POST("/upload", func(context *gin.Context) { file,err := context.FormFile("f1") if err != nil { context.JSON(http.StatusInternalServerError,gin.H{ "msg":err.Error(), }) } log.Println(file.Filename) dst := fmt.Sprintf("D:/temp/%s",file.Filename) context.SaveUploadedFile(file,dst) context.JSON(http.StatusOK,gin.H{ "msg":fmt.Sprintf(`%s uploaded!`,file.Filename), }) }) eng.Run() }
多個文件上傳:

package main import ( "fmt" "github.com/gin-gonic/gin" "log" "net/http" ) func main() { eng :=gin.Default() eng.POST("/upload", func(context *gin.Context) { // 多文件 form,_ := context.MultipartForm() files := form.File["f1"] for idx,file := range files{ log.Printf(file.Filename) dst := fmt.Sprintf("D:/temp/%s_%d",file.Filename,idx) context.SaveUploadedFile(file,dst) context.JSON(http.StatusOK,gin.H{ "msg":fmt.Sprintf(`%s uploaded!`,file.Filename), }) } }) eng.Run() }

<!DOCTYPE html> <html lang="zh-CN"> <head> <title>上傳文件示例</title> </head> <body> <form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data"> <input type="file" name="f1" multiple> <input type="submit" value="上傳"> </form> </body> </html>
Gin 的重定向:

package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { eng :=gin.Default() eng.GET("/test", func(context *gin.Context) { context.Redirect(http.StatusMovedPermanently,"http://www.baidu.com") }) eng.Run() }
Gin 的請求的轉發:

package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { eng :=gin.Default() eng.GET("/a", func(context *gin.Context) { context.Request.URL.Path = "/b" eng.HandleContext(context) }) eng.GET("/b", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{ "msg":"ok2", }) }) eng.Run() }
Gin 的路由:
context.Any() 可以接受任何方式的請求,
context.NoRoute() 處理沒有匹配的路由,404 請求,

package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { eng :=gin.Default() eng.LoadHTMLGlob("templates/*") eng.NoRoute(func(context *gin.Context) { context.HTML(http.StatusNotFound,"404.html",nil) }) eng.Run() }
路由組:
習慣性一對{}
包裹同組的路由,只是為了看着清晰,用不用{}
包裹功能上沒什么區別。

package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { eng :=gin.Default() eng.LoadHTMLGlob("templates/*") eng.NoRoute(func(context *gin.Context) { context.HTML(http.StatusNotFound,"404.html",nil) }) userGroup := eng.Group("/user") { userGroup.GET("/index", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"user_index"}) }) userGroup.GET("/login", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"user_login"}) }) } adminGroup := eng.Group("/admin") { adminGroup.GET("/index", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"admin_index"}) }) adminGroup.GET("/login", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"admin_login"}) }) } eng.Run() }
路由組也可以嵌套:

package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { eng :=gin.Default() eng.LoadHTMLGlob("templates/*") eng.NoRoute(func(context *gin.Context) { context.HTML(http.StatusNotFound,"404.html",nil) }) userGroup := eng.Group("/user") { userGroup.GET("/index", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"user_index"}) }) userGroup.GET("/login", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"user_login"}) }) vipGroup := userGroup.Group("/vip") { vipGroup.GET("/index", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"user_vip_index"}) }) vipGroup.GET("/login", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"user_vip_login"}) }) } } adminGroup := eng.Group("/admin") { adminGroup.GET("/index", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"admin_index"}) }) adminGroup.GET("/login", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"admin_login"}) }) } eng.Run() }
Gin 的綁定數據到結構體上:
form表單,json格式,

package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) type myData struct { Username string `form:"username" json:"user" binding:"required"` Password string `form:"password" json:"pwd" binding:"required"` } func main() { eng :=gin.Default() eng.POST("/", func(context *gin.Context) { var d myData // Content-type 為 multipart/form-data // POST 表單上傳 //err := context.Bind(&d) // Bind 可以解析form 格式 //if err != nil { // fmt.Println("bind data to struct failed,err:",err) // return //} //fmt.Println(d.Username) //fmt.Println(d.Password) //Content-type 為 application/json 格式 err := context.ShouldBindUri(&d) if err != nil { fmt.Println("bind data to struct failed,err:",err) return } fmt.Println(d.Username) fmt.Println(d.Password) context.JSON(http.StatusOK,gin.H{"msg":"ok"}) }) eng.Run() }
uri:(path 路徑)

package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) type myData struct { Username string `uri:"name" binding:"required"` Password string `uri:"pwd" binding:"required"` } func main() { eng :=gin.Default() eng.GET("/:name/:pwd", func(context *gin.Context) { var d myData err := context.ShouldBindUri(&d) if err != nil { fmt.Println("bind data to struct failed,err:",err) return } fmt.Println(d.Username) fmt.Println(d.Password) context.JSON(http.StatusOK,gin.H{"msg":"ok"}) }) eng.Run() }
Gin 的中間件:
全局中間件(contex.Next() 和 context.Abort() )

package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" "time" ) // 請求耗時的中間件函數 func countReqTime()gin.HandlerFunc { return func(context *gin.Context) { start := time.Now() m := make(map[string]interface{}) m["name"] = "tom" m["age"] = 18 context.Set("data",m) // 可以通過context.Set在請求上下文中設置值,后續的處理函數能夠取到該值 time.Sleep(time.Second) res := time.Since(start) fmt.Println("耗時:",res) context.Next() } } // 打印 hello world 的中間件 func printHello()gin.HandlerFunc { return func(context *gin.Context) { fmt.Println("hello world") context.Next() // 如果使用 context.Abort() 請求會到此返回,洋蔥模型 } } func main() { eng :=gin.Default() // 注冊兩個全局中間件 eng.Use(printHello()) eng.Use(countReqTime()) // {} 是為了代碼規范 eng.GET("/", func(context *gin.Context) { fmt.Println(context.Get("data")) context.JSON(http.StatusOK,gin.H{"msg":"ok"}) }) eng.Run() }
局部中間件(給單個路由 設置中間件)

package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) // 打印 hello world 的中間件 func printHello()gin.HandlerFunc { return func(context *gin.Context) { fmt.Println("hello world") context.Next() // 如果使用 context.Abort() 請求會到此返回,洋蔥模型 } } func main() { eng :=gin.Default() eng.GET("/",printHello(), func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"ok"}) }) eng.Run() }
給路由組加上中間件:

package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" ) func printHello() gin.HandlerFunc { return func(context *gin.Context) { fmt.Println("hello world") context.Next() } } func main() { eng :=gin.Default() eng.LoadHTMLGlob("templates/*") eng.NoRoute(func(context *gin.Context) { context.HTML(http.StatusNotFound,"404.html",nil) }) // 方式一 //userGroup := eng.Group("/user",printHello()) //{ // userGroup.GET("/index", func(context *gin.Context) { // context.JSON(http.StatusOK,gin.H{"msg":"user_index"}) // }) // userGroup.GET("/login", func(context *gin.Context) { // context.JSON(http.StatusOK,gin.H{"msg":"user_login"}) // }) //} // 方式二 userGroup := eng.Group("/user") userGroup.Use(printHello()) { userGroup.GET("/index", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"user_index"}) }) userGroup.GET("/login", func(context *gin.Context) { context.JSON(http.StatusOK,gin.H{"msg":"user_login"}) }) } eng.Run() }
默認中間件:
Gin 的獲取設置Cookie:

package main import ( "fmt" "github.com/gin-gonic/gin" ) func main() { eng :=gin.Default() eng.GET("/", func(context *gin.Context) { // 獲取客戶端cookie cookie,err := context.Cookie("xxx") if err != nil { fmt.Println("get cookie failed,err:",err) // 給客戶端設置 cookie // name, value string, maxAge(過期時間) int, path, domain string, secure(是否https), httpOnly(是否允許通過js 獲取cookie) bool context.SetCookie("xxx","value_cookie",60,"/","localhost",false,false) return } fmt.Println(cookie) }) eng.Run() }
Go Session:
https://files.cnblogs.com/files/zach0812/go%E7%9A%84session.zip
處理請求使用異步:

package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" "time" ) func main() { eng :=gin.Default() // 1 異步 eng.GET("/", func(context *gin.Context) { // 不能直接使用 context 上下文 copyCtx := context.Copy() go func() { time.Sleep(3*time.Second) fmt.Println("async",copyCtx.Request.URL) }() context.JSON(http.StatusOK,gin.H{"msg":"ok"}) }) // 2 同步 eng.GET("/2", func(context *gin.Context) { time.Sleep(3*time.Second) fmt.Println("sync",context.Request.URL) context.JSON(http.StatusOK,gin.H{"msg":"ok"}) }) eng.Run() }
Go 的 html/template 標准庫 模板渲染:
模板語法 和 自定義函數 和 嵌套HTML:

package main import ( "fmt" "html/template" "net/http" ) type userInfo struct { Name string Sex string Age int } // 自定義一個函數 func myFunc (arg string) string{ return "hello "+arg+" ;this is my function!" } func sayHello(response http.ResponseWriter,request *http.Request) { tmpl,err := template.New("hello.html").Funcs(template.FuncMap{"myFunc":myFunc}).ParseFiles("./hello.html","./test.html") if err != nil { fmt.Println("create template failed,err:",err) return } user := userInfo{ Name: "tom", Sex: "男", Age:18, } m := make(map[string]interface{}) m["user"]= user m["hobby"] = []string{"Basketball","Movie"} tmpl.Execute(response,m) } func main() { http.HandleFunc("/",sayHello) err := http.ListenAndServe(":9000",nil) if err != nil { fmt.Println("HTTP server failed,err:",err) return } }

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Hello</title> </head> <body> <h3>我靠,無情</h3> <p>Name {{.user.Name}}</p> <p>Sex {{.user.Sex}}</p> <p>Age {{.user.Age}}</p> <hr> <ul> {{range $idx,$hobby := .hobby}} <li>{{$idx}} --- {{$hobby}}</li> {{end}} </ul> <ul> {{range .hobby}} <li>{{.}}</li> {{end}} </ul> <hr> <p>{{$v1 := 0}}</p> <p>{{$v1}}</p> <p>{{$age := .user.Age}}</p> <p>{{$age}}</p> <hr> {{if $v1}} <p>Hello</p> {{else}} <p>World</p> {{end}} <hr> {{with .user}} <p>{{.Name}}</p> <p>{{.Age}}</p> <p>{{.Sex}}</p> {{end}} <hr> <h3>自定義函數</h3> {{myFunc "tom"}} <hr> <h3>嵌套其他的 template</h3> {{template "test.html"}} <hr> {{template "test02.html"}} <hr> </body> </html> {{ define "test02.html"}} <ol> <li>吃飯</li> <li>睡覺</li> <li>打豆豆</li> </ol> {{end}}

<ul> <li>注釋</li> <li>日志</li> <li>測試</li> </ul>
模板繼承:

package main import ( "fmt" "html/template" "net/http" ) func test(response http.ResponseWriter,request *http.Request) { tmpl,err := template.ParseFiles("base.html","index.html") if err != nil { fmt.Println("parse index.html failed,err:",err) return } name := "tom" //tmpl.Execute(response,name) tmpl.ExecuteTemplate(response,"index.html",name) } func main() { http.HandleFunc("/",test) err := http.ListenAndServe(":9000",nil) if err != nil { fmt.Println("HTTP server failed,err:",err) return } }

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{block "xx" .}} {{end}} </body> </html>

{{template "base.html" .}} {{define "xx"}} <h3>Hello {{.}}</h3> <div>Hello World</div> {{end}}
安全標簽:

package main import ( "fmt" "html/template" "net/http" ) func test(response http.ResponseWriter,request *http.Request) { tmpl,err := template.New("test.html").Funcs( template.FuncMap{ "safe": func(s string)template.HTML { return template.HTML(s) }, }).ParseFiles("./test.html") if err != nil { fmt.Println("parse test.html failed,err:",err) return } s := `<script>alert("hello world")</script>` tmpl.Execute(response,s) } func main() { http.HandleFunc("/",test) err := http.ListenAndServe(":9000",nil) if err != nil { fmt.Println("HTTP server failed,err:",err) return } }

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{. | safe}} </body> </html>
gorm :
官網: https://gorm.io/zh_CN/docs/
安裝:
go get -u github.com/jinzhu/gorm
初始化數據庫(mysql):

package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type Person struct { gorm.Model Name string Age int } func initDB()*gorm.DB { db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { fmt.Println("gorm open msyql failed,err",err) return nil } // 自動遷移 db.AutoMigrate(&Person{}) return db } func main() { db := initDB() defer db.Close() // 創建 //for i := 1; i < 20; i++ { // db.Create(&Person{Name: fmt.Sprintf("tom%d",i),Age: 18+i}) // time.Sleep(10*time.Second) //} }
建表:
指定名稱建表

package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type Book struct { gorm.Model Title string price float64 } func createTable(db *gorm.DB) { // 指定名稱 建表 db.Table("my_book").CreateTable(&Book{}) } func initDB()*gorm.DB { db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { fmt.Println("gorm open msyql failed,err",err) return nil } return db } func main() { db := initDB() defer db.Close() createTable(db) db.AutoMigrate(&Book{}) // 增 刪 改 查 }
增:

package main import ( "database/sql" "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type Person struct { gorm.Model Name sql.NullString `gorm:"default:'tom'"` Age int } func insert(db *gorm.DB) { //=================創建記錄==================== //db.Create(&Person{Name: "tommm",Age: 18}) // 關於默認值 相關 !!! // 如果通過 tag 定義字段的默認值,那么生成的 SQL 語句會排除沒有值或值為 零值 的字段。 將記錄插入到數據庫后,Gorm會從數據庫加載那些字段的值。 // 解決方法 :考慮使用指針或實現 Scanner/Valuer 接口 //db.Create(&Person{Name: "",Age: 22}) // 1,通過指針的方式 // 此時結構體應該: /* type Person struct { gorm.Model Name *string `gorm:"default:'tom'"` Age int } */ //db.Create(&Person{Name: new(string),Age: 33}) //2 通過實現 Scanner/Valuer 接口 // 此時結構體應該: /* type Person struct { gorm.Model Name *string `gorm:"default:'tom'"` Age int } */ //db.Create(&Person{Name: sql.NullString{String: "",Valid: true},Age: 44}) } func initDB()*gorm.DB { db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { fmt.Println("gorm open msyql failed,err",err) return nil } // 自動遷移 db.AutoMigrate(&Person{}) return db } func main() { db := initDB() defer db.Close() // 增 insert(db) }
查詢:
單表查詢:

package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type Person struct { gorm.Model Name string Age int } // 查詢 func query(db *gorm.DB) { //=================普通查詢==================== //1,第一條記錄 //var p Person //db.First(&p) //fmt.Println(p) //2,最后一條記錄 //var p Person //db.Last(&p) //fmt.Println(p) // 查詢指定的某條記錄(僅當主鍵為整型時可用) //var p Person //db.First(&p, 10) //fmt.Println(p) //3,全部數據 //var l []Person //db.Find(&l) //fmt.Println(l) //=================where 查詢==================== //4 where 條件 // 獲取第一個匹配的記錄 //var p Person //db.Where("name=?","tom").First(&p) //fmt.Println(p) // 獲取所有匹配的記錄 //var l []Person //db.Where("name=?","tom").Find(&l) //fmt.Println(l) // <> //var l []Person //db.Where("name <> ?","tom").Find(&l) //fmt.Println(l) // IN //var l []Person //db.Where("name IN (?)",[]string{"tom","tom2"}).Find(&l) //fmt.Println(l) // LIKE //var l []Person //db.Where("name LIKE ?","%tom_").Find(&l) //fmt.Println(l) // AND //var l []Person //db.Where("name = ? AND age > ?","tom",28).Find(&l) //fmt.Println(l) // Time //var l []Person //t := time.Now().Add(-time.Hour*2) // 兩小時之前 創建的 //db.Where("created_at < ?",t).Find(&l) //fmt.Println(l) // BETWEEN 【 】 //var l []Person //db.Where("age BETWEEN ? AND ?",25,30).Find(&l) //fmt.Println(l) //=================Not 條件==================== //var l []Person //db.Not("name","tom").Find(&l) //fmt.Println(l) // Not In //var l []Person //db.Not("name",[]string{"tom","tom11","tom18","tom19"}).Find(&l) //fmt.Println(l) //=================Or 條件==================== //var l []Person //db.Where("name='tom'").Or("age>32").Or("id<3").Find(&l) //fmt.Println(l) //=================高級查詢==================== //=================子查詢==================== //var l []Person //db.Where("age > ?", db.Table("people").Select("AVG(age)").SubQuery()).Find(&l) // person 表 存入數據庫中默認名字是 people //fmt.Println(l) //=================Select 選擇字段==================== //var l []Person //db.Find(&l)// 全部字段 //fmt.Println(l) //var l []Person //db.Select( "name,age").Find(&l) // 只有name age 有值 其余為nil //fmt.Println(l) //=================排序==================== //var l []Person //db.Order("name,age desc").Find(&l) // name 升序 age 降序 //fmt.Println(l) //=================Limit ==================== //var l []Person //db.Limit(3).Find(&l) //fmt.Println(l) //=================偏移==================== //開始返回記錄前要跳過的記錄數 //var l []Person //db.Offset(3).Limit(10).Find(&l) //fmt.Println(l) //=================Count==================== //var count int //var l []Person //db.Where("name='tom'").Find(&l).Count(&count) //fmt.Println(count) //db.Table("people").Where("name='tom'").Count(&count) // Count 必須是鏈式查詢的最后一個操作 //fmt.Println(count) //=================Group & Having==================== // Having 是 分組之后篩選 ,where 是分組之前篩選 //rows //rows, err := db.Table("people").Select("name,sum(age) as s").Group("name").Having("s>30").Rows() //if err != nil { // fmt.Println("group by name failed,err:",err ) // return //} //var name string //var s int //for rows.Next(){ // err := rows.Scan(&name,&s) // if err != nil { // fmt.Println(err) // return // } // fmt.Println(name,s) //} // 直接Scan //type temp struct { // Name string // S int //} //var l []temp //db.Table("people").Select("name,sum(age) as s").Group("name").Having("s>30").Scan(&l) //fmt.Println(l) //=================連接 Join (left join,right join,inner join ) ==================== // manager 表結構 id name addr //rows, _ := db.Table("people").Select("people.name,people.age, manager.addr").Joins("inner join manager on people.name = manager.name").Rows() //var name string //var age int //var addr string //for rows.Next() { // rows.Scan(&name,&age,&addr) // fmt.Println(name,age,addr) //} //type temp struct { // Name string // Age int // Addr string //} //var l []temp //db.Table("people").Select("people.name,people.age, manager.addr").Joins("inner join manager on people.name = manager.name").Scan(&l) //fmt.Println(l) } func initDB()*gorm.DB { db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { fmt.Println("gorm open msyql failed,err",err) return nil } // 自動遷移 db.AutoMigrate(&Person{}) return db } func main() { db := initDB() defer db.Close() // 查詢 //query(db) }
更新:

package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type Person struct { gorm.Model Name string Age int } func update(db *gorm.DB) { // 先找到 再修改 //================= 常用Update ==================== //================= 常用Update ==================== //================= 常用Update ==================== //================= 常用Update ==================== //================= 常用Update ==================== //================= 常用Update ==================== // 常用1 //db.Table("people").Where("id=12").Update("name","ahtom") // 常用2 //var p Person //db.Model(&p).Where("id=12").Update("name","yyytom") //=================Save 更新==================== // Save會更新所有字段,即使你沒有賦值 //var p Person //db.Where("id=10").Find(&p) //fmt.Println(p) //p.Name = "newtom" //db.Save(&p) //db.Where("id=10").Find(&p) //fmt.Println(p) //=================Update==================== //如果你只希望更新指定字段,可以使用Update或者Updates //var p Person //db.Where("id=11").Find(&p) //fmt.Println(p) // //db.Model(&p).Update("name","xxxtom") // //db.Where("id=11").Find(&p) //fmt.Println(p) //=================更新多個屬性==================== // 使用 struct 更新多個屬性,只會更新其中有變化且為非零值的字段 //var p Person //db.Model(&p).Where("id=12").Updates(Person{Name: "hellotomtom", Age: 19}) //// 警告:當使用 struct 更新時,GORM只會更新那些非零值的字段 //// 對於下面的操作,不會發生任何更新,"", 0, false 都是其類型的零值 //db.Model(&user).Updates(User{Name: "", Age: 0, Actived: false}) // 使用 map 更新多個屬性,只會更新其中有變化的屬性 //var p Person //db.Model(&p).Where("id=12").Updates(map[string]interface{}{"name": "hellotom", "age": 18}) //=================無Hooks 更新==================== //上面的更新操作會自動運行 model 的 BeforeUpdate, AfterUpdate 方法,更新 UpdatedAt 時間戳, 在更新時保存其 Associations, 如果你不想調用這些方法,你可以使用 UpdateColumn, UpdateColumns // 單個屬性 //var p Person //db.Model(&p).Where("id=14").UpdateColumn("name","zzztom") //fmt.Println(p) // 只返回更新的字段 // 多個屬性 //var p Person //db.Model(&p).Where("id=14").UpdateColumn(&Person{Name: "tomtom",Age: 22}) //fmt.Println(p) // 只返回更新的字段 //=================批量更新==================== //批量更新時 Hooks 不會運行 //db.Table("people").Where("id IN (?)", []int{10, 11,12,13}).Updates(&Person{Name: "hello0123", Age: 23}) //// UPDATE users SET name='hello0123', age=23 WHERE id IN (10, 11,12,13); // 使用 struct 更新時,只會更新非零值字段,若想更新所有字段,請使用map[string]interface{} //db.Table("people").Where("id IN (?)", []int{10, 11,12,13}).Updates(&Person{Name: "", Age: 23}) // 不能更新 零值字段 //db.Table("people").Where("id IN (?)", []int{10, 11,12,13}).Updates(map[string]interface{}{"name":"","age":10}) // 不能更新 零值字段 // 使用 `RowsAffected` 獲取更新記錄總數 //ret := db.Table("people").Where("id IN (?)", []int{10, 11,12,13}).Updates(&Person{Name: "xxxyyyzzz", Age: 23}).RowsAffected //fmt.Println(ret) //=================使用 SQL 表達式更新==================== //db.Table("people").Where("id=10").Update("age",gorm.Expr("age * ? + ?",2,10)) } func initDB()*gorm.DB { db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { fmt.Println("gorm open msyql failed,err",err) return nil } // 自動遷移 db.AutoMigrate(&Person{}) return db } func main() { db := initDB() defer db.Close() // 更新 update(db) }
刪除:

package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type Person struct { gorm.Model Name string Age int } func delete(db *gorm.DB) { //=================刪除==================== //警告 刪除記錄時,請確保主鍵字段有值,GORM 會通過主鍵去刪除記錄,如果主鍵為空,GORM 會刪除該 model 的所有記錄。 //db.Where("id=2").Delete(&Person{}) //=================批量刪除==================== // 刪除所有匹配的記錄 //db.Where("id IN (?)",[]int{10,11,12}).Delete(&Person{}) //=================軟刪除==================== //如果一個 model 有 DeletedAt 字段,他將自動獲得軟刪除的功能! 當調用 Delete 方法時, 記錄不會真正的從數據庫中被刪除, 只會將DeletedAt 字段的值會被設置為當前時間 // 查詢記錄時會忽略被軟刪除的記錄 //var l []Person //db.Where("id BETWEEN ? AND ?",1,20).Find(&l) //fmt.Println(l) //// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL; // Unscoped 方法 返回的是 包含 已經軟刪除的所有記錄 //var l []Person //db.Unscoped().Where("id BETWEEN ? AND ?",1,20).Find(&l) //fmt.Println(l) // 查詢deleted_at 是 NULL 的 記錄 (自己手工查的話) //var l []Person //db.Where("deleted_at is null").Find(&l) //fmt.Println(l) // 查詢已經被軟刪除的字段 //var l []Person //db.Unscoped().Where("deleted_at is not null").Find(&l) //fmt.Println(l) //=================物理刪除==================== //db.Unscoped().Where("id=1").Delete(&Person{}) // 真正刪除 該記錄 } func initDB()*gorm.DB { db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { fmt.Println("gorm open msyql failed,err",err) return nil } // 自動遷移 db.AutoMigrate(&Person{}) return db } func main() { db := initDB() defer db.Close() // 刪除 delete(db) }
一對一,一對多,多對多:

package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type Author struct { gorm.Model Name string Books []Book `gorm:"many2many:author_books;"` // Many to Many } // 一個Author 對應一個 AuthorInfo type AuthorInfo struct { gorm.Model Addr string Qq string Author Author // belongs to 如果寫在Author中就是 Has one // 一對一 AuthorID int `gorm:"unique"` // 一對一 } // 一個出版社出版 多本書 ,一本書只能由一個出版社出版 type Press struct { gorm.Model Name string Books []Book // Has Many // 一對多 } type Book struct { gorm.Model Title string PressID int // 一對多 Authors []Author `gorm:"many2many:author_books;"` // Many to Many } func initDB()*gorm.DB { db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { fmt.Println("gorm open msyql failed,err",err) return nil } return db } func main() { db := initDB() defer db.Close() db.AutoMigrate(&Author{},&AuthorInfo{},&Press{},&Book{}) //=================一對一==================== //一對一 創建 //author := Author{Name: "xxx"} //db.Create(&author) //db.Create(&AuthorInfo{Addr: "中山街大道",Qq: "1056768935",Author: author}) // 一對一 查詢 //var author Author //var info AuthorInfo //db.Find(&author,1) //db.Model(&author).Related(&info) //fmt.Println(info) //=================一對多==================== //一對多 創建 //book1 := Book{Title: "鋼鐵是怎樣煉成的"} //book2 := Book{Title: "紅樓夢"} //book3 := Book{Title: "西游記"} //db.Create(&book1) //db.Create(&book2) //db.Create(&book3) //db.Create(&Press{Name: "勝利出版社",Books: []Book{ // book1, // book2, // book3, //}}) // 一對多 查詢 //var press Press //var books []Book //db.Find(&press,1) //db.Model(&press).Related(&books) //fmt.Println(books) //=================多對多==================== // 創建多對多 // id為1 Book 是由 id 為1,2 的兩位作者寫的 //var author1 Author //var author2 Author //db.Find(&author1,1) //db.Find(&author2,2) // //var book Book //db.Find(&book,1) //book.Authors=[]Author{ // author1, // author2, //} //db.Save(&book) // id 為2 Book 是由 id 為1 的作者寫的 //var author1 Author //db.Find(&author1,1) // //var book Book //db.Find(&book,2) //book.Authors=[]Author{author1} //db.Save(&book) // id 為3 Book 是由 id 為2 的作者寫的 //var author1 Author //db.Find(&author1,2) // //var book Book //db.Find(&book,3) //book.Authors=[]Author{author1} //db.Save(&book) // 多對多 查詢 // 正向查詢 // id 為1的書 的作者都有誰 //var book Book //db.Find(&book,1) //var authors []Author //db.Model(&book).Related(&authors,"Authors") //fmt.Println(authors) // 查詢id 為1 的作者寫了哪幾本書 // 反向查詢 //var author Author //db.Find(&author,1) // //var books []Book //db.Model(&author).Related(&books,"Books") //fmt.Println(books) //===================================== // 數據庫中現在是: 作者1 寫了1,2 兩本書 作者2 寫了2,3兩本書 // 寫了 2這本書的 作者的 詳細信息 //var book Book //db.Find(&book,2) //var authors []Author //db.Model(&book).Related(&authors,"Authors") //fmt.Println(authors) //m := make(map[string]interface{},10) //for idx,author := range authors{ // var info AuthorInfo // db.Model(&author).Related(&info) // k := strconv.Itoa(idx) // temp := make(map[string]interface{},3) // temp["author_name"] = author.Name // temp["author_addr"] = info.Addr // temp["author_qq"] = info.Qq // m[k] = temp //} //author_data,_ := json.Marshal(m) //fmt.Println(string(author_data)) }