Go-Web 开发笔记
web 本质
一个请求对应一个响应。
Web 的本质可以概括为客户端与服务器之间的请求-响应模型。具体过程如下:
- 客户端发起请求:用户在浏览器中输入 URL 或点击链接,浏览器生成 HTTP 请求并发送到服务器。
- 服务器处理请求:服务器接收请求,解析后根据路径、参数等信息执行相应操作,如读取数据库或调用其他服务。
- 服务器返回响应:服务器生成 HTTP 响应,包含状态码、响应头和响应体(如 HTML、JSON 等数据),并发送回客户端。
- 客户端处理响应:浏览器接收响应,根据内容类型渲染页面或执行其他操作。
基础概念
前后端分离
他将一个传统的 \(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
Gorm 是 Golong 中最流行的 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}}
按照日期存储图片
- 获取上传的文件。
- 获取后缀名,判断类型是否正确。
- 创建图片保存目录。
- 生成文件名和文件保存的目录。
- 执行上传。
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)
- name
- 类型:
string - 描述: Cookie 的名称(key)。
- 类型:
- value
- 类型:
string - 描述: Cookie 的值。
- 类型:
- maxAge
- 类型:
int - 描述: Cookie 的过期时间(以秒为单位)。
- 注意: 如果只想设置 Cookie 的保存路径而不想设置存活时间,可以将此参数设置为
nil。
- 类型:
- path
- 类型:
string - 描述: Cookie 的路径。
- 类型:
- domain
- 类型:
string - 描述: Cookie 的作用域。
- 本地调试: 可以配置为
localhost。 - 正式上线: 应配置为域名。
- 类型:
- secure
- 类型:
bool - 描述: 当
secure值为true时,Cookie 仅在HTTPS连接中有效,在 HTTP 中无效。
- 类型:
- 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;

浙公网安备 33010602011771号