Go-Web 开发笔记

web 本质

一个请求对应一个响应。

Web 的本质可以概括为客户端与服务器之间的请求-响应模型。具体过程如下:

  1. 客户端发起请求:用户在浏览器中输入 URL 或点击链接,浏览器生成 HTTP 请求并发送到服务器。
  2. 服务器处理请求:服务器接收请求,解析后根据路径、参数等信息执行相应操作,如读取数据库或调用其他服务。
  3. 服务器返回响应:服务器生成 HTTP 响应,包含状态码、响应头和响应体(如 HTML、JSON 等数据),并发送回客户端。
  4. 客户端处理响应:浏览器接收响应,根据内容类型渲染页面或执行其他操作。

基础概念

前后端分离

他将一个传统的 \(Web\) 应用从一个整体拆分成两个独立的部分:前端、后端。

  • 前端:主要负责用户界面(UI)的呈现和交互逻辑。
  • 后端:主要负责业务逻辑、数据处理和数据库的交互。

优点

  • 提高开发效率。
  • 增强系统可维护性。
  • 提升用户体验。
  • 技术栈灵活。

前后端分离中 API 的作用

API 即为 Application Programming Interface (应用程序接口)。

RESTful API

REST:Represntational state Transfer(表述性状态转移),是一种软件架构风格,而非标准。

RESTful APi:为一种 REST 风格的接口,或者是满足 REST 风格的接口。

MVC

MVC:Model-View Controller,是一种常用的软件架构模式,旨在将应用程序的关注点分离,提高代码的可维护性。

用户操作 -> View -> Controller -> Model -> View。

URL

URL(Uniform Resource Locator, 统一资源定位器)。它是 www 的统一资源定位标志,简单地说URL就是web地址,俗称“网址”。

Gin

Gin 是一个使用 Go 语言开发的 Web 框架。

主要特点:

  • 高性能
  • 中间件支持
  • 路由分组

Gorm

GormGolong 中最流行的 ORM(对象关系映射)库(OMR Library)。

OMR - Object Relational Mapping

优势:

  • 简单易用
  • 自动迁移
  • 支持多种数据库

活用 Viper 读取配置文件

.yml文件介绍:

YAML 是"YAML Ain't a Markup Language"(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言),但为了强调这种语言以数据为中心, 而不是以标记语言为重点, 故改变名字。

例子:

receipt: InkkaPlum Channel
date: 2024

Gin 环境搭建

下载并安装 gin

go get -u github.com/gin-gonic/gin
package main

import "github.com/gin-gonic/gin"

func main() {
	//创建一个默认的路由引擎
	r := gin.Default()

	//配置路由
	r.GET("/", func(c *gin.Context) {
		c.String(200, "值 : %v", "Hello Gin!")
	})
	r.GET("/news", func(c *gin.Context) {
		c.String(200, "我是新闻页面")
	})

	//启动 Web 服务
	r.Run()
}

Golong 程序的 热加载

go install github.com/gravityblast/fresh@latest
>fresh

RESTful 架构中,每个网址代表一种资源,不同的请求方式表示执行不同的操作:

GET(SELECT) 从服务器取出资源(一项或多项)
POST(CREATE) 在服务器新建一个资源
PUT(UPDATE) 在服务器更新资源(客户端提供改变后的完整资源)
DELETE(DELETE) 从服务器删除资源

用GET返回字符串类型的数据

源码:

// String writes the given string into the response body.
func (c *Context) String(code int, format string, values ...any) {
	c.Render(code, render.String{Format: format, Data: values})
}

示例:

r.GET("/", func(c *gin.Context) {
	c.String(200, "val: %v", "首页")
})

用GET返回JSON类型的数据

源码:

// JSON serializes the given struct as JSON into the response body.
// It also sets the Content-Type as "application/json".
func (c *Context) JSON(code int, obj any) {
	c.Render(code, render.JSON{Data: obj})
}

示例:

	r.GET("/json1", func(c *gin.Context) {
		c.JSON(200, map[string]interface{}{
			"success": true,
			"msg":     "Hello Gin1",
		})
	})
	// gin.H == map[string]interface{}
	r.GET("/json2", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"success": true,
			"msg":     "Hello Gin2",
		})
	})
	
	/*
	type Article struct {
	Title   string `json:"title"`
	Desc    string `json:"desc"`
	Content string `json:"content"`
	}
	*/
	r.GET("/json3", func(c *gin.Context) {
		c.JSON(200, &Article{
			Title:   "title...",
			Desc:    "desc...",
			Content: "content...",
		})
	})

用GET返回JSONP类型的数据

后缀加上 ?callback=xxx

返回 json 数据前会输出 xxx({json})

...

用GET返回XML类型的数据

...

Gin HTML 模板渲染

配置模板的路径

 router.LoadHTMLGlob("templates/*")

源码:

// HTML renders the HTTP template specified by its file name.
// It also updates the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
func (c *Context) HTML(code int, name string, obj any) {
	instance := c.engine.HTMLRender.Instance(name, obj)
	c.Render(code, instance)
}

示例:

	r.GET("/news", func(c *gin.Context) {
		c.HTML(http.StatusOK, "news.html", gin.H{
			"title":   "title...",
			"desc":    "desc...",
			"content": "content...",
		})
	})

绑定后台数据:

main.go

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type Article struct {
	Title   string
	Content string
}

func main() {
	r := gin.Default()

	r.LoadHTMLGlob("templates/*")

	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{
			"title": "title...",
		})
	})

	r.GET("/news", func(c *gin.Context) {
		news := &Article{
			Title:   "news title...",
			Content: "news content",
		}
		c.HTML(200, "news.html", gin.H{
			"title": "news title",
			"news":  news,
		})
	})
	r.Run()
}

news.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2> {{.title}} </h2>
    <p> 
        {{.news.Title}}
    </p>
    <p>
        {{.news.Content}}
    </p>
</body>
</html>

对于加载模板文件在 templates 分散时的解决办法

路由配置改为:

r.LoadHTMLGlob("templates/**/*")

对应的 html 文件得改名

示例:

{{define "default/index.html"}}
//code...
{{end}}

Gin 模板的基本语法

{{.}} 输出数据

其他语句大概了解即可...

自定义模板函数导入

	//自定义模板函数,要放在加载模板之前
	r.SetFuncMap(template.FuncMap{
		"UnixToTime": UnixToTime,
	})

func UnixToTime(timestamp int) string {
	fmt.Println(timestamp)
	t := time.Unix(int64(timestamp), 0)
	return t.Format("2006-01-02 15:04:05")
}

POST请求传值

main.go

	//POST 演示
	r.GET("/user", func(c *gin.Context) {
		c.HTML(http.StatusOK, "user.html", gin.H{})
	})
	//获取表单 post 过来的数据
	r.POST("/doAddUser", func(c *gin.Context) {
		username := c.PostForm("username")
		password := c.PostForm("password")
		age := c.DefaultPostForm("age", "20")
		c.JSON(200, gin.H{
			"username": username,
			"password": password,
			"age":      age,
		})
	})

user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="/doAddUser" method="post">
        用户名:<input type="text" name="username"> <br> <br>
        密码:<input type="text" name="password"> <br> <br>

        <input type="submit" value="提交">
    </form>
</body>
</html>

Get 传值绑定到结构体

使用 ShouldBind

	// 获取 GET POST 传递的数据绑定到结构体
	r.GET("/getUser", func(c *gin.Context) {
		user := &UserInfo{}

		if err := c.ShouldBind(&user); err == nil {
			c.JSON(200, user)
		} else {
			c.JSON(200, gin.H{
				"err": err.Error(),
			})
		}

		// fmt.Printf("%#v", user)
	})

路由分组,Gin路由文件抽离

r.Group()路由分组

main.go

package main

import (
	"demo05/routers"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	routers.DefaultRoutersInit(r)

	routers.ApiRoutersInit(r)

	routers.AdminRoutersInit(r)

	r.Run()
}

./routers/default

package routers

import "github.com/gin-gonic/gin"

func DefaultRoutersInit(r *gin.Engine) {
	defaultRouters := r.Group("/")
	{
		defaultRouters.GET("/", func(c *gin.Context) {
			c.String(200, "首页")
		})

		defaultRouters.GET("/news", func(c *gin.Context) {
			c.String(200, "news ...")
		})
	}
}

./routers/adminRouters

package routers

import "github.com/gin-gonic/gin"

func AdminRoutersInit(r *gin.Engine) {
	adminRouters := r.Group("/admin")
	{
		adminRouters.GET("/", func(c *gin.Context) {
			c.String(200, "admin")
		})

		adminRouters.GET("/user", func(c *gin.Context) {
			c.String(200, "admin - userlist")
		})

		adminRouters.GET("/article", func(c *gin.Context) {
			c.String(200, "admin - article...")
		})
	}
}

./routers/apiRouters

package routers

import "github.com/gin-gonic/gin"

func ApiRoutersInit(r *gin.Engine) {
	apiRouters := r.Group("/api")
	{
		apiRouters.GET("/", func(c *gin.Context) {
			c.String(200, "API ...")
		})

		apiRouters.GET("/userlist", func(c *gin.Context) {
			c.String(200, "api - userlist...")
		})

		apiRouters.GET("/plist", func(c *gin.Context) {
			c.String(200, "api - plist...")
		})

		apiRouters.GET("/cart", func(c *gin.Context) {
			c.String(200, "adi - cart...")
		})
	}
}

Gin 中自定义控制器

func(c *gin.Context) {} 进行抽离。

adminRouters.go

package routers

import (
	"demo05/controllers/admin"

	"github.com/gin-gonic/gin"
)

func AdminRoutersInit(r *gin.Engine) {
	adminRouters := r.Group("/admin")
	{
		adminRouters.GET("/", admin.IndexController{}.Index)

		adminRouters.GET("/user", admin.UserController{}.Index)
		adminRouters.GET("/user/add", admin.UserController{}.Add)
		adminRouters.GET("/user/edit", admin.UserController{}.Edit)

		adminRouters.GET("/article", admin.ArticleController{}.Index)
		adminRouters.GET("/article/add", admin.ArticleController{}.Add)
		adminRouters.GET("/article/edit", admin.ArticleController{}.Edit)
	}
}

indexController.go

package admin

import "github.com/gin-gonic/gin"

type IndexController struct {
}

func (con IndexController) Index(c *gin.Context) {
	c.String(200, "admin")
}

articleController.go

package admin

import "github.com/gin-gonic/gin"

type ArticleController struct {
}

func (con ArticleController) Index(c *gin.Context) {
	c.String(200, "admin - article...")
}

func (con ArticleController) Add(c *gin.Context) {
	c.String(200, "admin - rticle - add")
}

func (con ArticleController) Edit(c *gin.Context) {
	c.String(200, "admin - rticle - edit")
}

userController.go

package admin

import "github.com/gin-gonic/gin"

type UserController struct {
}

func (con UserController) Index(c *gin.Context) {
	c.String(200, "admin - userlist")
}

func (con UserController) Add(c *gin.Context) {
	c.String(200, "admin - userlist - add")
}

func (con UserController) Edit(c *gin.Context) {
	c.String(200, "admin - userlist - edit")
}

Gin 中间件

r.GET("/", fun1()..., funn()) 最后一个 funn() 为路由的处理程序,其余 fun()为中间件。

c.Next() :中间件里面加上 c.Next() 可以让我们在路由匹配完成后执行一些操作,可以统计执行时间。

func initMiddleware(c *gin.Context) {
	start := time.Now().UnixNano()
	fmt.Println("middle - 1")

	c.Next()

	fmt.Println("middle - 2")
	end := time.Now().UnixNano()

	fmt.Println(end - start)
}

//adminRouters.GET("/user", initMiddleware, admin.UserController{}.Index)

c.Abort:终止剩余的待执行程序。

配置全局中间件 r.Use()

路由分组配置中间件:r.Gourp("/", middle...)

中间件间共享数据:ctx.Set()ctx.Get()

注意事项:中间件使用 goroutine 需要用 cCp = c.Copy()。不用可能会发生多个协程抢一个 context 的情况。

Gin 自定义 Model

MVC

  • M: Model -> 公共模块,数据,函数。
  • V: templates -> (View)视图。
  • C: Controller -> 控制器。

Gin 文件上传

单文件上传form + enctype="multipart/form-data"

html

{{ define "admin/useradd.html" }}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2>演示文件上传</h2>

    <form action="/admin/user/doUpload" method="post" enctype="multipart/form-data">
        用户名:<input type="text" name = "username" placeholder="用户名">
        <br>
        <br>
        头像:<input type="file" name = "face">
        <br>
        <br>
        <input type= "submit" value="提交">
    </form>
</body>
</html>

{{end}}

userController.go

func (con UserController) DoUpload(c *gin.Context) {
	username := c.PostForm("username")
	file, err := c.FormFile("face")
	//file.Filename 获取文件名称 aaa.jpg 拼接成 ./Upload/aaa.jpg
	dst := path.Join("./Upload", file.Filename)
	if err == nil {
		c.SaveUploadedFile(file, dst)
	}
	c.JSON(200, gin.H{
		"sucess":   true,
		"username": username,
		"dst":      dst,
	})
	c.String(200, "Upload...")
}

多文件不同名字上传

html

{{ define "admin/useredit.html" }}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2>演示不同名字的多文件上传</h2>

    <form action="/admin/user/doEdit" method="post" enctype="multipart/form-data">
        用户名: <input type="text" name = "username" placeholder="用户名">
        <br>
        <br>
        头像1: <input type="file" name = "face1">
        <br>
        <br>
        头像2: <input type="file" name = "face2">
        <br>
        <br>
        <input type= "submit" value="提交">
    </form>
</body>
</html>

{{end}}

userController.go

func (con UserController) DoEdit(c *gin.Context) {
	username := c.PostForm("username")

	file1, err1 := c.FormFile("face1")
	dst1 := path.Join("./Upload", file1.Filename)
	if err1 == nil {
		c.SaveUploadedFile(file1, dst1)
	}

	file2, err2 := c.FormFile("face2")
	dst2 := path.Join("./Upload", file2.Filename)
	if err2 == nil {
		c.SaveUploadedFile(file2, dst2)
	}

	c.JSON(200, gin.H{
		"sucess":   true,
		"username": username,
		"dst1":     dst1,
		"dst2":     dst2,
	})
}

多文件相同名字上传

userController.go

func (con UserController) DoUpload(c *gin.Context) {
	username := c.PostForm("username")

	form, _ := c.MultipartForm()
	files := form.File["face[]"]

	for _, file := range files {
		dst := path.Join("./Upload", file.Filename)
		// 上传文件至指定目录
		c.SaveUploadedFile(file, dst)
	}

	// file, err := c.FormFile("face")

	// //file.Filename 获取文件名称 aaa.jpg 拼接成 ./Upload/aaa.jpg
	// dst := path.Join("./Upload", file.Filename)
	// if err == nil {
	// 	c.SaveUploadedFile(file, dst)
	// }
	c.JSON(200, gin.H{
		"sucess":   true,
		"username": username,
		// "dst":      dst,
	})
	// c.String(200, "Upload...")
}

html

{{ define "admin/useradd.html" }}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2>演示文件上传</h2>

    <form action="/admin/user/doUpload" method="post" enctype="multipart/form-data">
        用户名:<input type="text" name = "username" placeholder="用户名">
        <br>
        <br>
        头像1: <input type="file" name = "face[]">
        <br>
        <br>
        头像2: <input type="file" name = "face[]">
        <br>
        <br>
        头像3: <input type="file" name = "face[]">
        <br>
        <br>
        <input type= "submit" value="提交">
    </form>
</body>
</html>

{{end}}

按照日期存储图片

  1. 获取上传的文件。
  2. 获取后缀名,判断类型是否正确。
  3. 创建图片保存目录。
  4. 生成文件名和文件保存的目录。
  5. 执行上传。

userController.go

func (con UserController) DoUpload(c *gin.Context) {
	username := c.PostForm("username")

	// 1.获取上传的文件。
	file, err := c.FormFile("face")

	if err == nil {
		// 2.获取后缀名,判断类型是否正确。
		extName := path.Ext(file.Filename)

		allowExtMap := map[string]bool{
			".jpg":  true,
			".png":  true,
			".gif":  true,
			".jpeg": true,
		}

		if _, ok := allowExtMap[extName]; !ok {
			c.String(200, "上传的文件不合法")
			return
		}
		// 3.创建图片保存目录。
		day := models.GetDay()

		dir := path.Join("./Upload", day)

		err := os.MkdirAll(dir, 0666)

		if err != nil {
			c.String(200, "MkdirAll Woring...")
			return
		}

		// 4.生成文件名和文件保存的目录。

		filename := strconv.FormatInt(models.GetUnix(), 10) + extName

		dst := path.Join(dir, filename)

		// 5.执行上传。

		c.SaveUploadedFile(file, dst)
	}

	c.JSON(200, gin.H{
		"sucess":   true,
		"username": username,
	})
}

Gin 中的 Cookie

c.SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)

  1. name
    • 类型: string
    • 描述: Cookie 的名称(key)。
  2. value
    • 类型: string
    • 描述: Cookie 的值。
  3. maxAge
    • 类型: int
    • 描述: Cookie 的过期时间(以秒为单位)。
    • 注意: 如果只想设置 Cookie 的保存路径而不想设置存活时间,可以将此参数设置为 nil
  4. path
    • 类型: string
    • 描述: Cookie 的路径。
  5. domain
    • 类型: string
    • 描述: Cookie 的作用域。
    • 本地调试: 可以配置为 localhost
    • 正式上线: 应配置为域名。
  6. secure
    • 类型: bool
    • 描述: 当 secure 值为 true 时,Cookie 仅在 HTTPS 连接中有效,在 HTTP 中无效。
  7. httpOnly
    • 类型: bool
    • 描述: 这是微软对 Cookie 的扩展。如果设置为 true,则通过 JavaScript 脚本等程序无法读取该 Cookie,有助于防止 XSS 攻击。

二级域名共享 cookie:修改 domain 的作用域即可。

Gin 中的 Session

Session 保存在服务器上,cookie 保存在客户端浏览器中。

需要引入 gin-contrib/sessions

"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
	//创建基于cookie的存储引擎,secret11111参数是用于加密的密钥
	store := cookie.NewStore([]byte("secret11111"))
	//设置session中间件,参数mysession,指的是session的名字,也是cookie的名字
	// store是前面创建的存储引擎,我们可以替换成其他存储引擎
	r.Use(sessions.Sessions("mysession", store))

将 Session 保存到 redis

redis 服务启动: redis-server.exe redis.windows.conf

redis 控制台启动:redis-cli

配置:

	store, _ := redis.NewStore(10, "tcp", "localhost:6379", "", []byte("secret"))
	r.Use(sessions.Sessions("mysession", store))

通过 session.Options() 可设置 session 的过期时间。

main.go

package admin

import (
	"demo08/models"
	"os"
	"path"
	"strconv"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
)

type UserController struct {
}

func (con UserController) Index(c *gin.Context) {
	// 获取sessions
	session := sessions.Default(c)
	username := session.Get("username")

	c.String(200, "admin - userlist session-username:%v", username)
}

func (con UserController) Add(c *gin.Context) {
	// 设置sessions
	session := sessions.Default(c)
	session.Set("username", "张三 111")
	session.Save() // 设置session的时候必须调用

	c.HTML(200, "admin/useradd.html", gin.H{})
}

func (con UserController) DoUpload(c *gin.Context) {
	username := c.PostForm("username")

	// 1.获取上传的文件。
	file, err := c.FormFile("face")

	if err == nil {
		// 2.获取后缀名,判断类型是否正确。
		extName := path.Ext(file.Filename)

		allowExtMap := map[string]bool{
			".jpg":  true,
			".png":  true,
			".gif":  true,
			".jpeg": true,
		}

		if _, ok := allowExtMap[extName]; !ok {
			c.String(200, "上传的文件不合法")
			return
		}
		// 3.创建图片保存目录。
		day := models.GetDay()

		dir := path.Join("./Upload", day)

		err := os.MkdirAll(dir, 0666)

		if err != nil {
			c.String(200, "MkdirAll Woring...")
			return
		}

		// 4.生成文件名和文件保存的目录。

		filename := strconv.FormatInt(models.GetUnix(), 10) + extName

		dst := path.Join(dir, filename)

		// 5.执行上传。

		c.SaveUploadedFile(file, dst)
	}

	c.JSON(200, gin.H{
		"sucess":   true,
		"username": username,
	})
}

userController.go

package admin

import (
	"demo08/models"
	"os"
	"path"
	"strconv"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
)

type UserController struct {
}

func (con UserController) Index(c *gin.Context) {
	// 获取sessions
	session := sessions.Default(c)
	username := session.Get("username")

	c.String(200, "admin - userlist session-username:%v", username)
}

func (con UserController) Add(c *gin.Context) {
	// 设置sessions
	session := sessions.Default(c)
	session.Set("username", "张三 111")
	session.Save() // 设置session的时候必须调用

	c.HTML(200, "admin/useradd.html", gin.H{})
}

func (con UserController) DoUpload(c *gin.Context) {
	username := c.PostForm("username")

	// 1.获取上传的文件。
	file, err := c.FormFile("face")

	if err == nil {
		// 2.获取后缀名,判断类型是否正确。
		extName := path.Ext(file.Filename)

		allowExtMap := map[string]bool{
			".jpg":  true,
			".png":  true,
			".gif":  true,
			".jpeg": true,
		}

		if _, ok := allowExtMap[extName]; !ok {
			c.String(200, "上传的文件不合法")
			return
		}
		// 3.创建图片保存目录。
		day := models.GetDay()

		dir := path.Join("./Upload", day)

		err := os.MkdirAll(dir, 0666)

		if err != nil {
			c.String(200, "MkdirAll Woring...")
			return
		}

		// 4.生成文件名和文件保存的目录。

		filename := strconv.FormatInt(models.GetUnix(), 10) + extName

		dst := path.Join(dir, filename)

		// 5.执行上传。

		c.SaveUploadedFile(file, dst)
	}

	c.JSON(200, gin.H{
		"sucess":   true,
		"username": username,
	})
}

MySQL 常用指令

数据库连接:mysql -uroot -p

1.显示当前存在的数据库。

show databases;

2.选择你需要操作的数据库

use name;

3.查看当前数据库有哪些数据表;

show tables;

4.查看一张表的所有内容

select * from user;

5.数据库设置中文编码

set names utf8;

6.创建一个数据库

create database book;

7.在创建数据库里创建一张表.

create table users(
	username varchar(20),
	sex int(1),
	status int(1)
);

8.显示表的结构

describe users;

9.给表插入一条数据。

insert into users(username, sex, status) values ("xiaomo", 1, 1)

10.根据条件筛选指定的数据

select * from users where username = 'xiaomo';

11.修改指定的数据

update users set status = 10 where username = 'haha';

12.删除指定的数据

delete from users where username = 'haha';

13.按照指定的数据排序

select * from users order by status desc; // 按照 status 倒序排序

升序的关键字是 asc

14.统计数量

select count(1) from users;
//统计第一列有多少条数据

15.Limit

select username, sex from users limit 2;
// 查前 2 条

select username, sex from users limit 2, 1;
// 跳过前 2 条,查 1 条

16.删除指定的表

drop table test;

17.删除指定的数据库

dorp database test;

准备:

1、创建一个班级数据库school,里面包含一张班级表class,包含编号(id)、 姓名(name)、邮件(email)、成绩(score)

create database school;

创建一个class表里面有id、name、email、score字段

CREATE TABLE class (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255),
email varchar(255),
score tinyint(4),
PRIMARY KEY (id)
);

PRIMARY KEY(id)表示 id 为主键,让 id 值唯一,不得重复。

2、给这个班级表 class 新增 5-10 条学员记录

INSERT INTO class VALUES(1,'张三','xiaomo@qq.com',89);
INSERT INTO class VALUES(2,'李四','441@qq.com',87);
INSERT INTO class VALUES(3,'王五','nodejs@qq.com',98);
INSERT INTO class VALUES(4,'赵四','java@qq.com',59);
INSERT INTO class VALUES(5,'小马','888@qq.com',66);
INSERT INTO class VALUES(6,'小李','999@hotmail.com',88);
INSERT INTO class VALUES(7,'小张','golang@163.com',55);

练习:

查看班级所有字段的记录以及查看班级 id,name 的记录

select * from class;

select id, name from class;

查找 email 不为空的数据

select * from class where email is not null;

查找 email 为空的数据

select * from class where email is null;

查找成绩大于等于70小于等于90的数据

select * from class where score >= 70 and score <= 90;

select * from class where score between 70 and 90;

查找 score 为 89 和 98 的数据

select * from class where score in (89, 98);

select * from class where score = 89 or score = 98;

查找score不是89和98的数据

select * from class where score not in (89, 98);

模糊查询

select * from class where email like "%qq%";

select * from class where email like "ja%";

select * from class where email like "%163.com";

select * from class where email not like "%163.com";

分组函数

统计班级的平均分

select avg(score) from class;

统计班级一共多少人

select count(1) from class;

找出这个班成绩最高的学生

select max(score) from class;

select * from class where score in (select max(score) from class);

找出这个班成绩最低的学生

select min(score) from class;

select * from class where score in (select min(score) from class);

统计这个班的总分

select sum(score) from class;

Mysql 别名

select name as a from class;

select min(score) as minscore from class;
posted @ 2025-03-22 22:43  XiaoMo247  阅读(38)  评论(0)    收藏  举报