Go Mod–我的理解
创建一个项目 在终端初始化一个mod go mod init 项目名(也可以是别的名字)然后自动创建一个.mod文件
然后 go get 包名 就可以下载相关的依赖 这样一来就不需要向gopath里导包 ,你下载的依赖以及依赖所需要的依赖都放在自动创建.sum文件中,.mod文件中就是你需要导入你项目的包
自己结构下的文件要加上init的名字 例如:原本的目录结构是 a/utils 这里要改成 initname/a/utils
----------------------------------------------------------------------------------
Web 入门------Hello Wrold
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/hello",handler) //路径为/hello 调用handler处理器
//路由器
http.ListenAndServe(":8080",nil) //端口8080 nil使用默认复用器
}
//处理函数
func handler(writer http.ResponseWriter,request *http.Request){
fmt.Fprintln(writer,"hello world")
}
连接MySQL数据库–实现增删改查
项目结构
db.go
package utils
import (
"database/sql"
_"github.com/go-sql-driver/mysql"
)
var(
Db *sql.DB
err error
)
func init() {
Db,err=sql.Open("mysql","root:root@tcp(localhost:3306)/lyf")
if err!=nil{
panic(err.Error())
}
}
users.go
package main
import (
"fmt"
"webstudy/DB_CURD/utils"
)
type User struct{
ID int
Username string
Password string
Email string
}
//********************增加*********************************
//预编译插入
func(u *User) Add() error{
//1、sql语句
sqlStr:="insert into users(username,password,email) values(?,?,?)"
//2、预编译
inStmt,err1:=utils.Db.Prepare(sqlStr)
if err1!=nil{
fmt.Println("预编译错误")
return err1
}
//3、执行
_,err2:=inStmt.Exec("ooo","666","1266621@qq.com")
if err2!=nil{
fmt.Println("执行错误")
return err2
}
return nil
}
//******************删除******************
func (u *User) Del(id int) bool{
//sql
sqlStr:="delete from users where id=?"
//预编译
stmt,err1:=utils.Db.Prepare(sqlStr)
if err1!=nil{
fmt.Println("预编译错误")
return false
}
res,err2:=stmt.Exec(id)
if err2!=nil{
fmt.Println("执行错误")
return false
}
num,err3:=res.RowsAffected()
if err3!=nil{
return false
}
fmt.Printf("影响行:%d",num)
return true
}
//**************************修改********************
func (u *User) Update(username string,password string,email string,id int) bool{
sqlStr:="update users set username=?,password=?,email=? where id=?"
stmt,err1:=utils.Db.Prepare(sqlStr)
if err1!=nil{
fmt.Println("预编译错误")
return false
}
res,err2:=stmt.Exec(username,password,email,id)
if err2!=nil{
fmt.Println("执行错误")
return false
}
num,err3:=res.RowsAffected()
if err3!=nil{
return false
}
fmt.Printf("影响行:%d",num)
return true
}
//*************************查询***************
//查询单条数据,QueryRow 函数
func (u *User) SelectOne(id int){
var username,password,email string
err:=utils.Db.QueryRow("select username,password,email from users where id=?",id).Scan(&username,&password,&email)
if err!=nil{
err.Error()
return
}
fmt.Println("username:",username,"password:",password,"email:",email)
}
//查询多条数据,并遍历
//Query 获取数据,for xxx.Next() 遍历数据
func (u *User) SelectAll(){
rows,err:=utils.Db.Query("select username,password,email from users")
if err!=nil{
err.Error()
return
}
for rows.Next(){
var username,password,email string
if err:=rows.Scan(&username,&password,&email);err==nil{
fmt.Println("username:",username,"password:",password,"email:",email)
}
}
}
func main() {
user:=&User{}
//user.Add()
//user.Del(1)
//user.Update("嗯嗯嗯","00000","iii@00.222","2")
//user.SelectOne(2)
user.SelectAll()
}
初探Gin框架
Templates 入门小例子
文件结构
第一步 定义模板
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>hello</title>
</head>
<body>
<p>Hello {{.}}</p> {{/* 语法:后端传入什么 后面那一块就是什么*/}}
</body>
</html>
第二部 解析模板
t,err:=template.ParseFiles("./templates/hello.tmpl")
if err!=nil{
fmt.Println("parse template err:",err)
return
}
第三步 渲染模板
name:="haha"
err2:=t.Execute(w,"哈哈哈哈哈"+name) //这里用"哈哈哈哈哈"+name 去替换模板里的{{.}}
if err2!=nil{
fmt.Println("execute err",err2)
return
}
整个代码块
package main
import (
"fmt"
"html/template"
"net/http"
)
//处理函数
func say(w http.ResponseWriter,r *http.Request){
//定义模板 在hello.tmpl文件中
//解析模板
t,err:=template.ParseFiles("./templates/hello.tmpl")
if err!=nil{
fmt.Println("parse template err:",err)
return
}
//渲染模板
name:="haha"
err2:=t.Execute(w,"哈哈哈哈哈"+name) //这里用"哈哈哈哈哈"+name 去替换模板里的{{.}}
if err2!=nil{
fmt.Println("execute err",err2)
return
}
}
func main() {
http.HandleFunc("/",say)
err:=http.ListenAndServe(":8080",nil)
if err!=nil{
fmt.Println("开启端口错误",err)
}
}
效果截图
自定义模板函数
目录结构
f1.tmpl
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>自定义函数模板</title>
</head>
<body>
{{haha .}} //haha是自己定义的模板函数
</body>
</html>
test.go (只给出了处理函数)
func handler(w http.ResponseWriter,r *http.Request){
k:= func(name string)string {
return name+"真帅!"
}
// 创建一个名字是f1的模板对象,名字要与模板名字相同(也可以直接template.New.Parse....)
t:=template.New("f1.tmpl")
//告诉模板引擎 我现在多了一个自定义的函数haha 一定要在解析模板之前
t.Funcs(template.FuncMap{
"haha":k,
})
//解析模板
_,err:=t.ParseFiles("f1.tmpl")
if err!=nil{
fmt.Println(err)
return
}
//渲染模板
en:="李一夫"
t.Execute(w,en)
}
模板的嵌套
u1.tmpl
<ul>
<li>注释</li>
<li>日志</li>
<li>测试</li>
</ul>
t.tmpl
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>测试嵌套templates</h1>
<hr>
{{/* 嵌套了另一个单独模板文件*/}}
{{template "ul.tmpl"}}
<hr>
{{/*嵌套另一个define定义的template模板*/}}
{{template "ol.tmpl"}}
<div>你好 , {{.}}</div>
</body>
</html>
{{/*****************************************************************************************/}}
{{/*通多define定义一个template模板*/}}
{{define "ol.tmpl"}}
<ol>
<li>唱</li>
<li>跳</li>
<li>rap</li>
</ol>
{{end}}
test.go(只给出了处理函数)
func handler02(w http.ResponseWriter,r *http.Request){
//解析模板
t,err:=template.ParseFiles("./t.tmpl","ul.tmpl")//把大的模板文件写在前面
if err!=nil{
fmt.Println(err)
return
}
//渲染模板
name:="李一夫"
t.Execute(w,name)
}
测试结果
模板的继承
例如此时我有A、B两个模板 他们的大致内容相同 我现在需要写两份高度相似的模板 浪费时间
现在我们可以写一个母板 然后A、B分别继承母板 只需要改动自己不同的那一小部分即可
test.go(只给出了处理函数部分)
func index02(w http.ResponseWriter,r *http.Request){
//解析模板
t,err:=template.ParseFiles("./templates/base.tmpl","./templates/index02.tmpl") //母板要放在前面
if err!=nil{
fmt.Println(err)
return
}
//渲染模板
name:="李一夫"
//需要告诉模板引擎我们渲染的是哪一个模板 要用ExecuteTemplate
t.ExecuteTemplate(w,"index02.tmpl",name)
}
func home02(w http.ResponseWriter,r *http.Request){
//解析模板
t,err:=template.ParseFiles("./templates/base.tmpl","./templates/home02.tmpl") //母板要放在前面
if err!=nil{
fmt.Println(err)
return
}
//渲染模板
name:="李一夫"
//需要告诉模板引擎我们渲染的是哪一个模板 要用ExecuteTemplate
t.ExecuteTemplate(w,"home02.tmpl",name)
}
base.tmpl(母板)
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>母板继承</title>
<style>
*{
margin: 0;
}
.nav{
height: 50px;
width: 100%;
position: fixed;
top: 0;
background-color: burlywood;
}
.main{
margin-top: 50px;
}
.menu{
width: 20%;
height: 100%;
position: fixed;
left: 0;
background-color: cornflowerblue;
}
.center{
text-align: center;
}
</style>
</head>
<body>
<div class="nav"></div>
<div class="main">
<div class="menu"></div>
<div class="content center">
{{/* block块 是被继承后需要改的 其他地方被继承后相同 后面的 . 不要忘记*/}}
{{/* "content 是块名"*/}}
{{block "content" .}}
{{end}}
</div>
</div>
</body>
</html>
index02.tmpl(继承模板)
{{/*继承跟模板 后面用来接收数据的 . 别忘记了*/}}
{{template "base.tmpl" .}}
{{/*重新定义块模板*/}}
{{define "content"}}
<h1>这是index页面</h1>
<p> hello {{.}}</p>
{{end}}
home02.tmpl(继承模板)
{{/*继承跟模板*/}}
{{template "base.tmpl" .}}
{{/*重新定义块模板*/}}
{{define "content"}}
<h1>这是home页面</h1>
<p> hello {{.}}</p>
{{end}}
template 自定义标识符
//Delims函数可以修改标识符
t,err:=template.New("hello.tmpl").Delims("{[","]}").ParseFiles("./hello.tmpl")
Gin 模板的渲染
目录结构
main.go(解析模板 于 加载静态文件部分(代码先后顺序改变了))
//解析模板
//r.LoadHTMLFiles("./template/index.tmpl")
//解析多个模板文件可以用下面的格式
r.LoadHTMLGlob("./template/**/*")//访问template目录下的所有子目录的文件
//路径为/index01时 用此匿名函数
r.GET("/index01",func(c *gin.Context){
// name是模板的名称,users实在.tmpl中起的别名,否则就是文件名 //H 是一个map
c.HTML(200,"users",gin.H{ //模板的渲染
"title":"我是index01",
})
})
//路径为/index01时 用此匿名函数
r.GET("/index02",func(c *gin.Context){
// name是模板的名称,posts实在.tmpl中起的别名,否则就是文件名 //H 是一个map
c.HTML(http.StatusOK,"posts",gin.H{ //模板的渲染
"title":"<a href='https://liwenzhou.com'>大佬的博客</a>",
})
})
//加载静态文件
r.Static("/ha","./statics") //.css文件中的路径要和relativePath相同 我的理解:将root路径起别名
//Gin框架中给模板自定义函数 要在解析之前
r.SetFuncMap(template.FuncMap{
"safe": func(str string)template.HTML { //该匿名函数 将字符串转为HTML格式
return template.HTML(str)
},
})
users/index.tmpl
{{/*起别名*/}}
{{define "users"}}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="./ha/index.css">
{{/* 引用 css文件*/}}
<title>Document</title>
</head>
<body>
{{.title}}
<script src="./ha/index.js"></script>
</body>
</html>
{{end}}
posts/index.tmpl
{{/*起别名*/}}
{{define "posts"}}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
{{.title | safe}}
{{/* | 是管道符号 类似于Linux中的用法 讲.title传来的数据用于safe方法*/}}
</body>
</html>
{{end}}
Gin框架返回json
json.go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
//*************************返回 json数据
func main() {
//创建默认路由引擎
r:=gin.Default()
r.GET("/json", func(c *gin.Context) {
//方法一:使用map
data:=map[string]interface{}{
"name":"李一夫",
"message":"hello world!",
"age":19,
}
//也可以使用下面的方法
//data:=gin.H{
// "name":"李一夫",
// "message":"hello world!",
// "age":19,
//}
c.JSON(http.StatusOK,data)
})
//方法二 : 结构体
type msg struct{
Name string `json:"name"` //用tag对结构体做定制化操作
Age int
Message string
}
r.GET("/struct", func(c *gin.Context) {
data:=msg{
Name: "李一夫",
Age: 19,
Message: "很帅",
}
c.JSON(http.StatusOK,data)
})
r.Run(":8080")
}
Gin 获取querystring参数
querystring参数就是 GET请求 URL ?后面的就是querystiring参数
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
//************gin 获取querystirng参数
func main() {
r:=gin.Default()
r.GET("/web", func(c *gin.Context) { //与请求相关的基本都 与 c参数有关
//获取浏览器发送请求携带的querystirng参数
name:=c.Query("query") //通过Query获取请求中的querystring参数 格式:get请求 url ?query=xxx,取得值就是xxx
age:=c.Query("age")
//name:=c.DefaultQuery("query","hahahha")//如果取不到 默认值就是"hahahah"
//name,ok:=c.GetQuery("query") //返回值时string,bool 取的到就取 取不到就给默认值
//if !ok{
// name="ennenen"
//}
c.JSON(http.StatusOK,gin.H{ //两个querystring参数可以用 & 来连接
"name":name,
"age":age,
})
})
r.Run(":8080")
}
Gin 获取form表单参数
第一个GET是处理以get请求访问的login路径 ,返回login.html 在login.html中通过post请求提交表单 ,再次通过POST方法处理以post请求访问的login路径,返回index.html
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="/login" method="post" novalidate autocomplete="off">
<label for="username">username:</label>
<input type="text" name="username" id="username">
<label for="password">password:</label>
<input type="password" name="password" id="password">
<input type="submit" value="登入">
</form>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hello {{.Name}}</h1>
<h1>你的密码是:{{.Password}}</h1>
</body>
</html>
form.go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
// *************Gin 获取form表单提交的参数
//一次请求对应一个响应
func main() {
r:=gin.Default()
r.LoadHTMLFiles("./login.html","./index.html")
//GET请求得到login.html里的格式 再用submit提交post请求时,则会再次新一次响应
r.GET("/login", func(c *gin.Context) {
c.HTML(http.StatusOK,"login.html",nil)
})
r.POST("/login", func(c *gin.Context) {
//获取form表单提交的数据
username:=c.PostForm("username") //key值是html中的name值
password:=c.PostForm("password")
//username:=c.DefaultPostForm("username","haha")没找到给默认值haha
//username,ok:=c.GetPostForm("username") //第二个参数 bool 是否取到
//if !ok{
// username="sb"
//}
c.HTML(http.StatusOK,"index.html",gin.H{
"Name":username,
"Password":password,
})
})
r.Run(":8080")
}
Gin获取URL路径参数
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
//************gin 获取url路径参数
func main() {
r:=gin.Default()
r.GET("/:name/:age", func(c *gin.Context) {
name:=c.Param("name")
age:=c.Param("age")
c.JSON(http.StatusOK,gin.H{
"name":name,
"age":age,
})
})
r.Run(":8080")
}
效果截图
Gin绑定参数
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
// gin参数绑定:因为从页面取数据时 需要放在结构体中,使用shouldBind可简化操作
type User struct {
Name string `form:"name" json:"name"`
Age string `form:"age" json:"age"`
Sex string `form:"sex" json:"sex"`
}
func main() {
r:=gin.Default()
//绑定querystring
r.GET("/hello", func(c *gin.Context) {
//***********使用下面的注释的步骤非常繁琐,要是结构体成员多,那就要写很多的c.Query方法
//name:=c.Query("name")
//age:=c.Query("age")
//sex:=c.Query("sex")
//u:=User{
// Name: name,
// Age: age,
// Sex: sex,
//}
//fmt.Println(u)
//c.JSON(http.StatusOK,"ok")
var u User
err:=c.ShouldBind(&u)
if err==nil{
fmt.Println(u)
c.JSON(http.StatusOK,"ok")
}else{
c.JSON(http.StatusBadRequest,gin.H{
"err":err.Error(),
})
}
})
//绑定form
r.POST("/hello", func(c *gin.Context) {
var u User
err:=c.ShouldBind(&u)
if err==nil{
fmt.Println(u)
c.JSON(http.StatusOK,"ok")
}else{
c.JSON(http.StatusBadRequest,gin.H{
"err":err.Error(),
})
}
})
//绑定json
r.POST("/json", func(c *gin.Context) {
var u User
err:=c.ShouldBind(&u)
if err==nil{
fmt.Println(u)
c.JSON(http.StatusOK,"ok")
}else{
c.JSON(http.StatusBadRequest,gin.H{
"err":err.Error(),
})
}
})
r.Run(":8080")
}
(1)绑定json在postman中执行
(2)绑定form表单在postman中执行
(3)绑定querystring表单在postman中执行
Gin 上传文件
package main
import (
"github.com/gin-gonic/gin"
"net/http"
"path"
)
//GIn 上传文件
func main() {
r:=gin.Default()
r.LoadHTMLFiles("./file.html")
r.GET("/file", func(c *gin.Context) {
c.HTML(http.StatusOK,"file.html",nil)
})
r.POST("/upload", func(c *gin.Context) {
//从请求中读取文件
f,err:=c.FormFile("f1")
if err!=nil{
c.JSON(http.StatusBadRequest,gin.H{
"err":err.Error(),
})
}else {
//将读取到的文件保存本地(服务端)
//filepath:=fmt.Sprintf("./%s",f.Filename) //也可以用下面的
filepath:=path.Join("./",f.Filename)
c.SaveUploadedFile(f,filepath)
c.JSON(http.StatusOK,"ok")
}
})
r.Run(":8080")
}
Gin重定向
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
//Gin重定向
//跳转到搜狗页面
func hello(c *gin.Context){
c.Redirect(http.StatusMovedPermanently,"http://www.sogo.com")
}
func main() {
r:=gin.Default()
r.GET("/index",hello)
r.GET("/a", func(c *gin.Context) {
//跳转到b对应的处理函数
c.Request.URL.Path="/b" //把请求的url更改
r.HandleContext(c) //继续后续的处理
})
//返回json
r.GET("/b", func(c *gin.Context) {
c.JSON(http.StatusOK,"ok")
})
r.Run(":8080")
}
路由与路由组
//这就是路由
r.GET("/index", func(c *gin.Context) {...})
r.GET("/login", func(c *gin.Context) {...})
r.POST("/login", func(c *gin.Context) {...})
//这个是特殊的 是一个大杂烩,包括很多路由 可以在内部用switch语句来选择用哪个路由
r.Any("/test", func(c *gin.Context) {...})
//路由组
func main() {
r := gin.Default()
//把共用前缀提取出来,创建一个路由组
userGroup := r.Group("/user")
{
userGroup.GET("/index", func(c *gin.Context) {...})
userGroup.GET("/login", func(c *gin.Context) {...})
userGroup.POST("/login", func(c *gin.Context) {...})
}
shopGroup := r.Group("/shop")
{
shopGroup.GET("/index", func(c *gin.Context) {...})
shopGroup.GET("/cart", func(c *gin.Context) {...})
shopGroup.POST("/checkout", func(c *gin.Context) {...})
}
//没有路由到的页面
r.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound,gin.H{
"err":"找不到你要的页面",
})
})
r.Run()
}
Gin中间件
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
//中间件 : 我的理解,类似于拦截器吧,比如你有n个页面,但是你需要让注册了账号的人才能访问,你不可能每一个页面中都写入if 是会员然后登入,
// 这时候就可以写一个中间件 浏览器---> 中间件 ---> 页面
//m1 相当于中间件 (统计处理函数的耗时时长)
func m1(c *gin.Context){
fmt.Println("执行m1中间件..")
//计时
start:=time.Now()
c.Next() //接着调用后面的处理函数 下一个是匿名的
//c.Abort() //阻止调用下一个处理函数
costtime:=time.Since(start) //从start到现在耗费的时间
fmt.Printf("耗费的时间是:%v \n",costtime)
fmt.Println("m1 执行完毕。。。")
}
func m2(c *gin.Context){
fmt.Println("执行m2。。。")
c.Set("name","李一夫") //在中间件创建值 使得处理函数可以拿到
c.Next()
fmt.Println("结束m2")
}
func main() {
r:=gin.Default()//默认使用了Logger()和Recovery()中间件
//r:=gin.New() //自定义一个空的路由引擎
//r.Use(m1) 全局注册m1中间件 下面就可以省略写m1
// 先执行m1 此时m1就相当于中间件
r.GET("/index", m1,m2,func(c *gin.Context) {
fmt.Println("执行handlerfun()")
name:=c.MustGet("name")
c.JSON(http.StatusOK,gin.H{
"msg":name,
})
})
r.Run(":9090")
}
Gorm框架学习
Gorm连接数据库以及模型的定义
package main
// 使用Gorm框架
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql" //驱动
)
type UserInfo struct {
Id uint `gorm:"primary_key"` //设置主键
Name string `gorm:"column:user_name"` //修改表字段名
Gender string `gorm:"default :'不详'"` //默认值,下面没有实例此字段或者设置字段为空,都会使用默认值
// 但会出现一个问题,如果我想把字段设为空值,但系统还是会使其默认为默认值
//解决方法1:可以将类型改为指针类型,在下面实例改为Gender: new(string) new()函数的作用是将对应类型变为相应的指针类型
//解决方法2:先将结构体字段改为Gender sql.NullString `gorm:"default :'不详'"`
// 再将下面实例改为 Gender: sql.NullString{String:"",Valid:true}(true的意思是空字符串)
Hobby string
}
//唯一指定表名 不自己定义表表名的话,系统会自动生成表名
func(UserInfo)TableName()string{
return "haha"
}
func main() {
//新建的默认表名都加上aaa_前缀
//gorm.DefaultTableNameHandler= func(db *gorm.DB, defaultTableName string) string {
// return "aaa_"+defaultTableName
//}
db,err:=gorm.Open("mysql","root:root@tcp(localhost:3306)/lyf?charset=utf8mb4&parseTime=True&loc=Local")
if err!=nil{
panic(err )
}
defer db.Close()
//在数据库自动创建表 自动迁移 (把结构体和数据表进行对应)
db.AutoMigrate(&UserInfo{})
//db.Table("liyifu").CreateTable(&UserInfo{}) 使用UserInfo结构体创建指定名字的表
//u1:=UserInfo{
// Id: 1,
// Name: "李一夫",
// Gender: "男",
// Hobby: "篮球",
//}
//创建数据行 类似于插入吧
//db.Create(&u1)
//查询
var user UserInfo
db.First(&user) //查询表中第一条数据 并保存到user中
fmt.Printf("user:%v\n",user)
//更新
db.Model(&user).Update("hobby","肉肉")
//删除
db.Delete(&user)
}
Gorm 的增删改查
具体看文档
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
//1、定义模板
type Person struct {
//gorm.Model //框架自带的四个字段 ID(主键id) CreatAt(创建时间) UpdataAt(修改时间) DeleteAt(删除时间)
ID int `gorm:primary_key`
Name string
Age int
}
func main() {
//连接MySQL数据库
db, err := gorm.Open("mysql", "root:root@tcp(localhost:3306)/lyf?charset=utf8")
if err != nil {
panic(err)
}
defer db.Close()
//2、把模板和数据库中的表对应
db.AutoMigrate(&Person{})
//3、插入数据
//p1:=Person{
// Name: "lyf",
// Age: 19,
//}
//db.Create(&p1)
//p2:=Person{Name:"whh",Age:19,}
//db.Create(&p2)
//********************查询
//if db.HasTable("people"){ 检测people表是否存在
// fmt.Println("存在表people")
//}
// 删除模型`Person`的表和表`people`
//db.DropTableIfExists(&Person{}, "people")
//var p Person
//db.Debug().First(&p,1)//查询id为1的数据 主键是数字才可以使用
//fmt.Printf("person: %#v \n",p)
//db.Debug().First(&p,"name=?","whh") //查询name为whh的数据
//fmt.Printf("person: %#v \n",p)
//db.Debug().First(&p) // 查询第一条数据 只适用于主键是数字
//fmt.Printf("person: %#v \n",p)
//var ps []Person
//db.Debug().Find(&ps) //任何操作前加一个Debug()可以看执行过程
//fmt.Printf("persons:%#v \n",ps)
//****************************where()查询
//查询第一个name=whh的数据
//db.Where("name=?","whh").First(&p)
//fmt.Println(p)
//查询所有age=19的数据
//db.Where("age=?","19").Find(&ps)
//fmt.Println(ps)
//模糊查询
//db.Where("name like ?","_h_").First(&p)
//fmt.Println(p)
//and
//db.Where("name = ? and age >= ?","whh","18").Find(&ps)
//fmt.Println(ps)
//or
//db.Where("name = ? or age >= ?","whh","18").Find(&ps)
//fmt.Println(ps)
//in
//db.Where("name in (?)",[]string{"whh","lyf","lyf22"}).Find(&ps)
//fmt.Println(ps)
//struct 于 map
// Struct
//db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
// Map
//db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
//db.Where(Person{Name: "whh"}).FirstOrInit(&p) FirstOrInit()没有就创造一个
// 查找的name为lyf的数据中没有age的值是则创键 有则不变
//db.Where(Person{Name: "lyf"}).Attrs(Person{Age: 20}).FirstOrInit(&p)
// 无论name为lyf的数据有没有age的值 都将30赋予
//db.Where(Person{Name: "lyf"}).Assign(Person{Age: 30}).FirstOrInit(&p)
//db.Select("id, age").Find(&ps)
//fmt.Println(ps)
// SELECT name, age FROM people;
//排序
//db.Order("age desc, name").Find(&ps)
SELECT * FROM users ORDER BY age desc, name;
//limit 指定查询几条记录
//db.Limit(3).Find(&ps)
//offset 跳过前几条数据
//db.Offset(3).Find(&ps)
//count 获取一共有多少条记录
//var count int
//db.Select("id,age").Find(&ps).Count(&count)
//fmt.Println(count)
//分组 group
//rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
//*************************更新
//var p Person
//var ps []Person
//save() 无论是否赋值 全部更新
//db.First(&p)
//fmt.Println(p)
//p.Name="mzyf"
//p.Age=20
//db.Save(&p)
//fmt.Println(p)
//update() 修改单个字段值
//db.Model(&p).Update("name","baba").Where("name=?","mzyf")
//db.First(&p)
//fmt.Println(p)
// 使用结构体修改多个值
// 使用 map 更新多个属性,只会更新其中有变化的属性
//db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
// 使用 struct 更新多个属性,只会更新其中有变化且为非零值的字段
//db.Model(&user).Updates(User{Name: "hello", Age: 18})
//******************删除
//var p Person
var ps []Person
//db.Delete(&p) 删除所有
//db.Find(&ps)
//fmt.Println(ps)
}