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 ", 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)) }