Go语言中http和mysql的实现代码
IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《Go语言中http和mysql的实现代码》,聊聊MySQL、go语言http,我们一起来看看吧!
http 编程
Go 原生支持http:
import "net/http"
Go 的http服务性能和nginx比较接近:
就是说用Go写的Web程序上线,程序前面不需要再部署nginx的Web服务器,这里省掉的是Web服务器。如果服务器上部署了多个Web应用,还是需要反向代理的,一般这也是nginx或apache。
几行代码就可以实现一个web服务:
package main
import (
"fmt"
"net/http"
)
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Println(*r)
fmt.Fprintf(w, "Hello World")
}
func main() {
http.HandleFunc("/", Hello)
err := http.ListenAndServe("0.0.0.0:8000", nil)
if err != nil {
fmt.Println("http Listen failed")
}
}
http client
http 常见的请求方法:
- Get请求
- Post请求
- Put请求
- Delete请求
- Head请求
Get 请求
使用Get请求网站的示例:
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
res, err := http.Get("http://edu.51cto.com")
if err != nil {
fmt.Println("http get ERRPR:", err)
return
}
data, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println("get data ERROR:", err)
return
}
fmt.Println(string(data))
}
Head请求
Head请求只返回响应头。如果只想要获取一些状态信息的话,可以用Head请求。这样避免返回响应体,响应体的数据是比较多的,适合做监控。Head请求的示例:
package main
import (
"fmt"
"net/http"
)
var urls = []string{
"http://×××w.baidu.com",
"http://×××w.google.com",
"http://×××w.sina.com.cn",
"http://×××w.163.com",
}
func main() {
for _, v := range urls {
resp, err := http.Head(v)
if err != nil {
fmt.Println("Head request ERROR:", err)
continue
}
fmt.Println(resp.Status)
}
}
http 常见状态码
http.StatusContinue = 100
http.StatusOK = 200
http.StatusFound = 302 跳转
http.StatusBadRequest = 400 非法请求
http.StatusUnanthorized = 401 没有权限
http.StatusForbidden = 403 禁止访问
http.Status.NotFound = 404 页面不存在
http.StatusInternalServerError = 500 内部错误
处理form表单
package main import ( "fmt" "io" "net/http" ) const form = `` func FormServer(w http.ResponseWriter, request *http.Request) { w.Header().Set("content-Type", "text/html") switch request.Method { case "GET": io.WriteString(w, form) case "POST": request.ParseForm() io.WriteString(w, request.Form["in"][0]) // 注意上面的2个input的name是一样的 io.WriteString(w, request.Form["in"][1]) // 所以这是一个数组 io.WriteString(w, "") io.WriteString(w, request.FormValue("in")) // 一般去一个值,就用这个方法 } } func main() { http.HandleFunc("/form", FormServer) if err := http.ListenAndServe(":8000", nil); err != nil { fmt.Println("监听端口ERROR:", err) } }
panic 处理
如果处理函数里有panic,会导致整个程序崩溃,所以要 defer revoer() 来处理 panic。在处理函数开头defer一个匿名函数:
func FormServer(w http.ResponseWriter, request *http.Request) {
// 增加一个defer来处理panic
defer func() {
if x := recover(); x != nil {
log.Println(request.RemoteAddr, "捕获到异常:", x)
}
}()
// 原本的处理函数的内容
w.Header().Set("content-Type", "text/html")
switch request.Method {
case "GET":
io.WriteString(w, form)
case "POST":
request.ParseForm()
io.WriteString(w, request.FormValue("in")) // 一般去一个值,就用这个方法
}
// 搞个panic出来
zero := 0
tmp := 1 / zero
io.WriteString(w, string(tmp))
}
优化统一处理
按照上面的做法,要在每个处理函数的开头都加上panic的处理。由于每个处理函数的panic处理方法都一样,所以可以写一个自定义的处理函数:
// 自定义的panic处理的函数
func logPanics(handle http.HandlerFunc) http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
defer func() {
if x := recover(); x != nil {
log.Println(request.RemoteAddr, "捕获到异常:", x)
}
}()
// 上面先处理panic,再接着下面调用业务逻辑
handle(writer, request)
}
}
func main() {
// http.HandleFunc("/form", FormServer) // 修改调用处理函数的方法
http.HandleFunc("/form", logPanics(FormServer)) // 把处理函数传给自己写的封装了panic处理的函数里
if err := http.ListenAndServe(":8000", nil); err != nil {
fmt.Println("监听端口ERROR:", err)
}
}
原本直接调用处理函数。现在调用自定义的函数,把处理函数传进去。在自定义的函数里先加载defer,然后再调用执行原本的处理函数。逻辑很简单,就是把处理函数作为参数传给自定义的函数,在自定义的函数里再调用处理函数。在自定义的函数里写上defer,这样就相当于所有的处理函数都有defer了。
模板
使用模板需要用到 "text/template" 包。然后调用模板的t.Execute()方法输出。
替换
先准备一个简单的模板:
<p>Hello {{.Name}}</p>
<p>Age: {{.Age}}</p>
然后在Go里使用模板:
package main
import (
"fmt"
"os"
"text/template"
)
type Person struct {
Name string
Age int
}
func main() {
t, err := template.ParseFiles("index.html")
if err != nil {
fmt.Println("模板解析异常:", err)
return
}
p := Person{"Bob", 32}
if err := t.Execute(os.Stdout, p); err != nil {
fmt.Println("模板加载数据异常:", err)
}
}
/* 执行结果
PS H:\Go\src\go_dev\day10\http\use_template> go run main.go
<p>Hello Bob</p>
<p>Age: 32</p>
PS H:\Go\src\go_dev\day10\http\use_template>
*/
如果直接用 {{.}} 不加字段名的话,就是输出结构体打印的效果。
输出到浏览器里
要输出到浏览器里,只需要在 t.Execute(os.Stdout, p) 里,把原本输出到终端换成输出到处理函数的 w http.ResponseWriter 类型,就好了。
html模板的内容不变,下面是go的代码:
package main
import (
"fmt"
"net/http"
"text/template"
)
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World")
}
type Person struct {
Name string
Age int
}
func Index(w http.ResponseWriter, r *http.Request) {
p := Person{"Cara", 18}
t, err := template.ParseFiles("index.html")
if err != nil {
fmt.Println("加载模板ERROR:", err)
return
}
t.Execute(w, p)
}
func main() {
http.HandleFunc("/", Hello)
http.HandleFunc("/index", Index)
err := http.ListenAndServe("0.0.0.0:8000", nil)
if err != nil {
fmt.Println("http Listen failed")
}
}
判断
用法示例:
{{if gt .Age 18}}
<p>已成年</p>
{{else}}
<p>未成年</p>
{{end}}
更多判断逻辑:
not 非
{{if not .condition}}
{{end}}
and 与
{{if and .condition1 .condition2}}
{{end}}
or 或
{{if or .condition1 .condition2}}
{{end}}
eq 等于
{{if eq .var1 .var2}}
{{end}}
ne 不等于
{{if ne .var1 .var2}}
{{end}}
lt 小于
{{if lt .var1 .var2}}
{{end}}
le 小于等于
{{if le .var1 .var2}}
{{end}}
gt 大于
{{if gt .var1 .var2}}
{{end}}
ge 大于等于
{{if ge .var1 .var2}}
{{end}}
with 封装
with语句就是创建一个封闭的作用域,在其范围内,{{.}}代表with的变量,而与外面的{{.}}无关,只与with的参数有关:
{{with .Name}}
<p>{{.}}</p>
{{end}}
上面这样包在 {{with .Var}} 里,with 里的 {{.}} 代表的就是 Var 这个变量。
with 可以封装常数:
{{ with "world"}}
Now the dot is set to {{ . }}
{{ end }}
循环(遍历)
golang的template支持range循环来遍历map、slice内的内容,在range循环内,还可以使用$设置循环变量,我们可以通过 $i $v 来访问遍历的值。语法为:
{{range $i, $v := .slice}}
这是另外一种遍历方式,这种方式无法访问到index或者key的值,需要通过点来访问对应的value:
{{range .slice}}
{{.field}}
{{end}}
在循环内,点是代表遍历的值。原本使用点来访问的变量,那么在循环内部就要用 $. 来访问。下面的例子表示循环内和循环外 ArticleConten 这个变量访问的方式:
{{.ArticleContent}}
{{range .slice}}
{{$.ArticleContent}}
{{end}}
定义变量
模板的参数可以是go中的基本数据类型,如字串,数字,布尔值,数组切片或者一个结构体。在模板中设置变量可以使用 $variable := value。我们在range迭代的过程使用了设置变量的方式。
{{$article := "hello"}}
{{$name := .Name}}
mysql 使用
这里只简单讲了数据的增删改查,所以测试代码前,需要先把数据库准备好。
先创建一个数据库,指定了编码,这样应该可以支持中文:
CREATE DATABASE 库名 CHARSET "utf8";
然后建2张表:
CREATE TABLE person ( user_id int primary key auto_increment, username varchar(260), gender varchar(260), email varchar(260) ); CREATE TABLE place ( country varchar(200), city varchar(200), telcode int );
导入数据库驱动
sql 包提供了通用的SQL(或类SQL)数据库接口。
sql 包必须与数据库驱动结合使用。
驱动包需要安装:
go get -u github.com/go-sql-driver/mysql
使用前,先要导入mysql的包:
import ( "database/sql" _ "github.com/go-sql-driver/mysql" )
上面导入了2个包。第一个是sql包,就是我们调用操作数据库用的。
第二个是驱动包,这里前面加了占位符,所以这个包只是引入,但是不使用它。并且如果要操作别的数据库的话,只需要修改驱动包就行了。
连接数据库
构建连接, 格式是:”用户名:密码@tcp(IP:端口)/数据库?charset=utf8” :
package main
import (
"fmt"
"time"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
var DB *sql.DB
func init() {
database, err := sql.Open("mysql", "admin:admin123@tcp(192.168.3.103:3306)/Golang_week10")
if err != nil {
fmt.Println("连接数据库失败:", err)
return
}
DB = database
}
func main() {
fmt.Println(DB)
DB.SetMaxIdleConns(16) //设置闲置连接数
DB.SetMaxOpenConns(100) //设置最大连接数
DB.SetConnMaxLifetime(100*time.Second) //最大连接周期,超过时间的连接就close
fmt.Println(DB)
}
插入数据
下面是插入数据,并且再获取id的示例:
// 数据库连接的init函数就省略了
func insert() {
r, err := DB.Exec("insert into person(username,gender,email) values(?,?,?)", "Barry", "Male", "Barry@go.net")
if err != nil {
fmt.Println("插入数据ERROR:", err)
return
}
fmt.Println(r)
id, err := r.LastInsertId()
if err != nil {
fmt.Println("获取id ERROR:", err)
return
}
fmt.Println(id)
}
func main() {
insert()
}
上面的 values(?,?,?) 里的问号,是占位符,具体的值可以写在后面的参数里。当然如果不用占位符,直接就传1个字符串作为参数也是可以的。
查询
查询单个字段:
func query() {
row := DB.QueryRow("select username from person where user_id=?", 1)
var name string // 创建变量用于存放查询到的数据
if err := row.Scan(&name); err != nil {
fmt.Println("Scan Failed:", err)
return
}
fmt.Println(name)
}
func main() {
query()
}
也可以一次查询多个字段或所有字段,查询之前按照表的类型创建结构体,用查询到的数据为结构体赋值:
type Person struct {
ID int `db:"user_id"`
Username sql.NullString `db:"username"`
Gender sql.NullString `db:"gender"`
Email sql.NullString `db:"email"`
}
func query() {
row := DB.QueryRow("select * from person where user_id=?", 6)
var person = new(Person)
// row.scan中的字段必须是按照数据库存入字段的顺序,否则报错
if err := row.Scan(&person.ID, &person.Username, &person.Gender, &person.Email); err != nil {
fmt.Println("Scan Failed:", err)
return
}
fmt.Println(person)
}
func main() {
query()
}
数据模型,就是上面定义的结构体。这里的类型可以是Go的标准数据类型。但是如果数据库的字段允许为空,并且该字段的值也为空,那么查询后该字段会返回nil。如果是string类型,则无法接收nil,但sql.NullString则可以接收nil值。
另外,结构体里的tag标签在这里没有意义。不过上面的tag标注了该字段在数据库里对应的字段名,可能在别处会有用。
查询多行
func query() {
rows, err := DB.Query("select * from person where user_id > ?", 1)
defer func() {
if rows != nil {
rows.Close()
}
}()
if err != nil {
fmt.Println("Query 查询 ERROR:", err)
return
}
var person = new(Person)
for rows.Next() {
if err = rows.Scan(&person.ID, &person.Username, &person.Gender, &person.Email); err != nil {
fmt.Println("Scan Failed:", err)
return
}
fmt.Println(person)
}
}
func main() {
query()
}
查询用起来还是不太方法,不过还可以选择其他第三方库,那里会有一些很好的扩展。后面会举例。
其他操作
由于基本都是用SQL的命令进行操作,所以其他操作就不一个一个举例了
update 更新数据
result, err := DB.Exec("UPDATE person set email=? where username=?", "Cara", <a target='_blank' href='https://www.17golang.com/gourl/?redirect=MDAwMDAwMDAwML57hpSHp6VpkrqbYLx2eayza4KafaOkbLS3zqSBrJvPsa5_0Ia6sWuR4Juaq6t9nq5raZiRkLFox93WfI2Kgc21e3_MnKqyr4TTaam8q32errKFmoqAjmi0p6dojoailb54etyGla6jhdCbZLGGmKCys5yafbOHpLO6s2qNrKKi' rel='nofollow'>Cara@catco.org</a>)
delete 删除数据
result,err := DB.Exec("DELETE FROM person where id=?",1)
注意:更新数据不返回LastInsertID,所以result.LastInsertID一直为0。删除数据可以拿到LastInsertID,用法和插入数据里一样。
第三方库 sqlx
sqlx是一个go语言包,在内置database/sql包之上增加了很多扩展,简化数据库操作代码的书写。
由于database/sql接口是sqlx的子集,所有database/sql的用法,在sqlx中一样可以用。不过sqlx还有更多扩展,用起来更方便。
安装:
go get github.com/jmoiron/sqlx
查询 Select() 方法
Select是一个非常省时的扩展。它们把query和非常灵活的scan语法结合起来。Select用来获取结果切片:
// 这里的tag标签就有意义了,下面的Select()方法应该就是根据tag标签对号入座的
type Person struct {
ID int `db:"user_id"`
Username sql.NullString `db:"username"`
Gender sql.NullString `db:"gender"`
Email sql.NullString `db:"email"`
}
func select() {
var persons []Person // 这里创建的是存放结构体的切片
if err := DB.Select(&person, "select * from person where userid > ?", 1); err != nil {
fmt.Println("Select ERROR:", err)
return
}
fmt.Println(person)
}
Select可以提高编码效率,还有更多扩展。sqlx 号称 golang 数据库开发神器,这里就提一下,等到真正用的时候再去深入学习了。
以上就是《Go语言中http和mysql的实现代码》的详细内容,更多关于golang的资料请关注golang学习网公众号!
用gomock进行mock测试的方法示例
- 上一篇
- 用gomock进行mock测试的方法示例
- 下一篇
- golang gorm 操作mysql及gorm基本用法
-
- Golang · Go教程 | 7分钟前 |
- Golang并发测试与goroutine性能分析
- 456浏览 收藏
-
- Golang · Go教程 | 14分钟前 |
- Go语言scanner包:位移与空格识别解析
- 213浏览 收藏
-
- Golang · Go教程 | 16分钟前 |
- Golang适配器模式与接口转换技巧
- 371浏览 收藏
-
- Golang · Go教程 | 17分钟前 |
- Golang文件备份实现教程详解
- 105浏览 收藏
-
- Golang · Go教程 | 25分钟前 |
- Golang文件上传服务器搭建教程
- 125浏览 收藏
-
- Golang · Go教程 | 26分钟前 |
- Go语言自定义类型长度限制技巧
- 161浏览 收藏
-
- Golang · Go教程 | 28分钟前 |
- Golang反射实战教程详解
- 412浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- GolangCI/CD测试流程实现详解
- 347浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Golang模块冲突解决全攻略
- 200浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go语言处理JSON浮点数编码技巧
- 391浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Golangselect多路复用实战教程详解
- 307浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3168次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3381次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3410次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4514次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3790次使用
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- 搞一个自娱自乐的博客(二) 架构搭建
- 2023-02-16 244浏览
-
- B-Tree、B+Tree以及B-link Tree
- 2023-01-19 235浏览
-
- mysql面试题
- 2023-01-17 157浏览
-
- MySQL数据表简单查询
- 2023-01-10 101浏览

