栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

Go-Web基础入门教程(含源码)【第四篇】数据库编程及路由

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Go-Web基础入门教程(含源码)【第四篇】数据库编程及路由

简介

来源于B站视频,知识点整理的第四篇包含数据库编程及路由部分
课程视频
如需查看上篇内容请看:
Go-Web基础入门教程(含源码)【第三篇】

Go Web

Web是基于http协议的一个服务,Go语言里面提供了一个完善的net/http包,通过http包可以很方便的就搭建起来一个可以运行的Web服务。

补充 - Go数据库编程

如果没有下载数据库相关的引用,则需要在控制台输入
go get github.com/go-sql-driver/mysql

	package main
	
	import (
		"context"
		"database/sql"
		"fmt"
		"log"
	
		_ "github.com/go-sql-driver/mysql"
	)
	
	var db *sql.DB
	
	const (
		server   = "127.0.0.1"
		port     = 3306
		user     = "root"
		password = "root"
		database = "eesy"
	)
	
	func main() {
		// 需要改成你自己数据库的配置
		db, _ := sql.Open("mysql", "db:db@(127.0.0.1:3306)/dbname")
		err := db.Ping()
		if err != nil {
			log.Fatalln(err.Error())
		}
		defer db.Close()
		ctx := context.Background()
		err = db.PingContext(ctx)
		if err != nil {
			log.Fatalln(err.Error())
		}
		fmt.Println("Connected!")
	}

想要连接SQL数据库,首先需要加载目标数据库的驱动,驱动中包含着与该数据库交互的逻辑.

  • sql.Open()
    • 数据库驱动的名称
    • 数据源的名称
    • 得到一个指向sql.DB这个strcut的指针
    • sql.DB对象对于多个 goroutine 并发使用是安全的

sql.DB是用来操作数据库的,实际上代表了0个或者多个底层连接池,这些连接由SQL包来维护,SQL包会自动创建和释放这些连接.


如何获取驱动?
正常的做法是通过sql.Register()函数,数据库驱动的名称以及一个实现了driver.Driver接口的struct来注册数据库的驱动.例如:

  • sql.Register("mysql", &drv{})

驱动的自动注册概念

  • 当 go-sql-driver/mysql包被引入的时候,它的init函数会运行并且进行自我注册
  • 在引入包的开始位置使用_ 是因为我们不直接使用数据库驱动,只使用database/sql
    • 这样设计的好处在于即使驱动需要升级也无需改变代码
  • Go语言没有提供官方的数据库驱动,所有的数据库驱动都是第三方驱动,它们都遵循sql.driver包里面定义的接口

SQL - 查询
  • sql.DB类型上用于查询的方法:
    • Query把查询SQL语句发送到数据库
    • QueryRow适用于只有一条记录的方法
    • QueryContext:携带上下文信息
    • QueryRowContext:携带上下文信息

Query方法:

QueryRow方法:

案例使用的数据库表结构如下:

表中的数据如下:

案例一:查询演练
案例总共包含三个文件分别是:model.go + service.go + main.go

// model.go
package main

type user struct {
	Id       int
	username string
	pwd      string
}

// service.go
package main

import (
	"log"
)

// 查询单一结果
func getOne(id int) (u user, err error) {
	u = user{}
	log.Println(db == nil)
	err = db.QueryRow("SELECt id, username, password FROM user WHERe id = ?", id).Scan(
		&u.Id, &u.username, &u.pwd)
	return
}

// 查询多个结果
func getMany(id int) (us []user, err error) {
	// 返回类型为 sql.Rows - 可以理解为一个迭代器
	rows, err := db.Query("SELECt id, username, password FROM user WHERe id > ?", id)
	for rows.Next() {
		u := user{}
		err = rows.Scan(&u.Id, &u.username, &u.pwd)
		if err != nil {
			log.Fatalln(err.Error())
		}
		us = append(us, u)
	}
	return
}



// main.go
package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

func main() {
	// 如果里面使用 db, err := ... 会导致内部同局部变量覆盖全局变量
	var err error
	// 需要改成你自己数据库的配置
	db, err = sql.Open("mysql", "db:db@(127.0.0.1:3306)/dbname")
	if err != nil {
		log.Fatalln(err.Error())
	}
	ctx := context.Background()
	err = db.PingContext(ctx)
	if err != nil {
		log.Fatalln(err.Error())
	}
	fmt.Println("Connected!")
	log.Println(db == nil)
	one, err := getOne(2)
	fmt.Println(one)
	many, err := getMany(0)
	fmt.Println(many)
}
SQL - 更新及删除


案例:需要在 service.go 中添加如下方法:

func (u *user) Update() (err error) {
	_, err = db.Exec("UPDATE user SET username = ? WHERe id = ?", u.username, u.Id)
	if err != nil {
		log.Fatalln(err.Error())
	}
	return
}

func (u *user) Delete() (err error) {
	_, err = db.Exec("DELETE FROM user WHERe id = ?", u.Id)
	if err != nil {
		log.Fatalln(err.Error())
	}
	return
}
SQL - 其他补充知识

func (u *user) Insert() (err error) {
	// 建立 SQL 语句模板 
	statement := `INSERT INTO user (id, username, password) VALUES (?, ?, ?)`
	stmt, err := db.Prepare(statement)
	defer stmt.Close()
	if err != nil {
		log.Fatalln(err.Error())
	}
	stmt.QueryRow(u.Id, u.username, u.pwd)
	fmt.Println("Insert success!")
	return
}
08 - 路由 Controller层介绍

案例:抽取Controller层
当前案例的结构如下:

  • main.go
package main

import (
   "go_code/project03_go_web/demo08router/controller"
   "net/http"
)

func main() {
   controller.RegisterRoutes()
   http.ListenAndServe("localhost:8888", nil)
}
  • html

	{{ define "content" }}
	

About

{{ . }} {{ end }} {{ define "content" }}

Home

{{ . }} {{ end }} {{ define "layout"}} Layout {{ template "content" .}} {{ end }}

  • controller
// about.go
package controller

import (
	"html/template"
	"net/http"
)

func registerAboutRoutes() {
	http.HandleFunc("/about", handleAbout)
}

func handleAbout(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("layout.html", "about.html")
	// 因为在模板里面使用 define 重新命名了模板,所以使用的时候需要传入定义的名称.
	t.ExecuteTemplate(rw, "layout", "")
}

// home.go
package controller

import (
	"html/template"
	"net/http"
)

func registerHomeRoutes() {
	http.HandleFunc("/home", handleHome)
}

func handleHome(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("layout.html", "home.html")
	// 因为在模板里面使用 define 重新命名了模板,所以使用的时候需要传入定义的名称.
	t.ExecuteTemplate(rw, "layout", "Hello!")
}

// controller.go
package controller

func RegisterRoutes() {
	registerHomeRoutes()
	registerAboutRoutes()
}
路由参数

  • main.go
package main

import (
   "go_code/project03_go_web/demo08router/controller"
   "net/http"
)

func main() {
   controller.RegisterRoutes()
   http.ListenAndServe("localhost:8888", nil)
}
  • html

	{{ define "content" }}
	

About

{{ . }} {{ end }} {{ define "content" }}

Home

{{ . }} {{ end }} {{ define "layout"}} Layout {{ template "content" .}} {{ end }} {{ define "content"}}

Company: {{ . }}

{{ end }} {{ define "content"}}

All Companies

  • Microsoft
  • Google
  • Apple
{{ end }}
  • controller
// about.go
package controller

import (
	"html/template"
	"net/http"
)

func registerAboutRoutes() {
	http.HandleFunc("/about", handleAbout)
}

func handleAbout(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("layout.html", "about.html")
	// 因为在模板里面使用 define 重新命名了模板,所以使用的时候需要传入定义的名称.
	t.ExecuteTemplate(rw, "layout", "")
}

// home.go
package controller

import (
	"html/template"
	"net/http"
)

func registerHomeRoutes() {
	http.HandleFunc("/home", handleHome)
}

func handleHome(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("layout.html", "home.html")
	// 因为在模板里面使用 define 重新命名了模板,所以使用的时候需要传入定义的名称.
	t.ExecuteTemplate(rw, "layout", "Hello!")
}

// controller.go
package controller

func RegisterRoutes() {
	registerHomeRoutes()
	registerAboutRoutes()
	registerCompanyRoutes()
}

// company.go
package controller

import (
	"fmt"
	"net/http"
	"regexp"
	"strconv"
	"text/template"
)

func registerCompanyRoutes() {
	http.HandleFunc("/companies", handlerCompanies)
	http.HandleFunc("/companies/", handlerCompany)
}

func handlerCompanies(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("layout.html", "companies.html")
	t.ExecuteTemplate(w, "layout", nil)
}

func handlerCompany(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("layout.html", "company.html")
	pattern, _ := regexp.Compile(`/companies/(d+)`)
	matches := pattern.FindStringSubmatch(r.URL.Path)
	if len(matches) > 0 {
		fmt.Println(matches[0])
		companyID, _ := strconv.Atoi(matches[1])
		t.ExecuteTemplate(w, "layout", companyID)
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}
第三方路由器
  • gorilla/mux:灵活性高、功能强大、性能相对差一些
  • httprouter:注重性能、功能简单
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/944437.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号