最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言中http和mysql的實(shí)現(xiàn)代碼

 更新時間:2018年11月26日 08:37:55   作者:騎士救兵  
本文通過實(shí)例代碼給大家介紹了Go語言中http和mysql的實(shí)現(xiàn)代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下

http 編程

Go 原生支持http:

import "net/http"

Go 的http服務(wù)性能和nginx比較接近:

就是說用Go寫的Web程序上線,程序前面不需要再部署nginx的Web服務(wù)器,這里省掉的是Web服務(wù)器。如果服務(wù)器上部署了多個Web應(yīng)用,還是需要反向代理的,一般這也是nginx或apache。

幾行代碼就可以實(shí)現(xiàn)一個web服務(wù):

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請求網(wǎng)站的示例:

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請求只返回響應(yīng)頭。如果只想要獲取一些狀態(tài)信息的話,可以用Head請求。這樣避免返回響應(yīng)體,響應(yīng)體的數(shù)據(jù)是比較多的,適合做監(jiān)控。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 常見狀態(tài)碼

http.StatusContinue = 100

http.StatusOK = 200

http.StatusFound = 302 跳轉(zhuǎn)

http.StatusBadRequest = 400 非法請求

http.StatusUnanthorized = 401 沒有權(quán)限

http.StatusForbidden = 403 禁止訪問

http.Status.NotFound = 404 頁面不存在

http.StatusInternalServerError = 500 內(nèi)部錯誤

處理form表單

package main

import (
 "fmt"
 "io"
 "net/http"
)

const form = `
<html>
<body>
<form action="#" method="post" name="bar">
 <input type="text" name="in" />
 <input type="text" name="in" />
 <input type="submit" value="Submit" />
</form>
</body>
</html>`

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]) // 所以這是一個數(shù)組
  io.WriteString(w, "</br>")
  io.WriteString(w, request.FormValue("in")) // 一般去一個值,就用這個方法
 }
}

func main() {
 http.HandleFunc("/form", FormServer)
 if err := http.ListenAndServe(":8000", nil); err != nil {
  fmt.Println("監(jiān)聽端口ERROR:", err)
 }
}

panic 處理

如果處理函數(shù)里有panic,會導(dǎo)致整個程序崩潰,所以要 defer revoer() 來處理 panic。在處理函數(shù)開頭defer一個匿名函數(shù):

func FormServer(w http.ResponseWriter, request *http.Request) {
 // 增加一個defer來處理panic
 defer func() {
  if x := recover(); x != nil {
   log.Println(request.RemoteAddr, "捕獲到異常:", x)
  }
 }()
 // 原本的處理函數(shù)的內(nèi)容
 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))
}

優(yōu)化統(tǒng)一處理

按照上面的做法,要在每個處理函數(shù)的開頭都加上panic的處理。由于每個處理函數(shù)的panic處理方法都一樣,所以可以寫一個自定義的處理函數(shù):

// 自定義的panic處理的函數(shù)
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,再接著下面調(diào)用業(yè)務(wù)邏輯
  handle(writer, request)
 }
}

func main() {
 // http.HandleFunc("/form", FormServer) // 修改調(diào)用處理函數(shù)的方法
 http.HandleFunc("/form", logPanics(FormServer)) // 把處理函數(shù)傳給自己寫的封裝了panic處理的函數(shù)里
 if err := http.ListenAndServe(":8000", nil); err != nil {
  fmt.Println("監(jiān)聽端口ERROR:", err)
 }
}

原本直接調(diào)用處理函數(shù)?,F(xiàn)在調(diào)用自定義的函數(shù),把處理函數(shù)傳進(jìn)去。在自定義的函數(shù)里先加載defer,然后再調(diào)用執(zhí)行原本的處理函數(shù)。邏輯很簡單,就是把處理函數(shù)作為參數(shù)傳給自定義的函數(shù),在自定義的函數(shù)里再調(diào)用處理函數(shù)。在自定義的函數(shù)里寫上defer,這樣就相當(dāng)于所有的處理函數(shù)都有defer了。

模板

使用模板需要用到 "text/template" 包。然后調(diào)用模板的t.Execute()方法輸出。

替換

先準(zhǔn)備一個簡單的模板:

<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("模板加載數(shù)據(jù)異常:", err)
 }
}

/* 執(zhí)行結(jié)果
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>
*/

如果直接用 {{.}} 不加字段名的話,就是輸出結(jié)構(gòu)體打印的效果。

輸出到瀏覽器里

要輸出到瀏覽器里,只需要在 t.Execute(os.Stdout, p) 里,把原本輸出到終端換成輸出到處理函數(shù)的 w http.ResponseWriter 類型,就好了。

html模板的內(nèi)容不變,下面是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")
 }
}

判斷

用法示例:

<body>
{{if gt .Age 18}}
<p>已成年</p>
{{else}}
<p>未成年</p>
{{end}}
</body>

更多判斷邏輯:

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語句就是創(chuàng)建一個封閉的作用域,在其范圍內(nèi),{{.}}代表with的變量,而與外面的{{.}}無關(guān),只與with的參數(shù)有關(guān):

<body>
{{with .Name}}
<p>{{.}}</p>
{{end}}
</body>

上面這樣包在 {{with .Var}} 里,with 里的 {{.}} 代表的就是 Var 這個變量。

with 可以封裝常數(shù):

{{ with "world"}}
 Now the dot is set to {{ . }}
{{ end }}

循環(huán)(遍歷)

golang的template支持range循環(huán)來遍歷map、slice內(nèi)的內(nèi)容,在range循環(huán)內(nèi),還可以使用$設(shè)置循環(huán)變量,我們可以通過 $i $v 來訪問遍歷的值。語法為:

{{range $i, $v := .slice}}
 <li>key: {{ $key }}, value: {{ $value }}</li>
{{end}}

這是另外一種遍歷方式,這種方式無法訪問到index或者key的值,需要通過點(diǎn)來訪問對應(yīng)的value:

{{range .slice}}
{{.field}}
{{end}}

在循環(huán)內(nèi),點(diǎn)是代表遍歷的值。原本使用點(diǎn)來訪問的變量,那么在循環(huán)內(nèi)部就要用 $. 來訪問。下面的例子表示循環(huán)內(nèi)和循環(huán)外 ArticleConten 這個變量訪問的方式:

{{.ArticleContent}}
{{range .slice}}
{{$.ArticleContent}}
{{end}}

定義變量

模板的參數(shù)可以是go中的基本數(shù)據(jù)類型,如字串,數(shù)字,布爾值,數(shù)組切片或者一個結(jié)構(gòu)體。在模板中設(shè)置變量可以使用 $variable := value。我們在range迭代的過程使用了設(shè)置變量的方式。

{{$article := "hello"}}
{{$name := .Name}}

mysql 使用

這里只簡單講了數(shù)據(jù)的增刪改查,所以測試代碼前,需要先把數(shù)據(jù)庫準(zhǔn)備好。

先創(chuàng)建一個數(shù)據(jù)庫,指定了編碼,這樣應(yīng)該可以支持中文:

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
);


導(dǎo)入數(shù)據(jù)庫驅(qū)動

sql 包提供了通用的SQL(或類SQL)數(shù)據(jù)庫接口。

sql 包必須與數(shù)據(jù)庫驅(qū)動結(jié)合使用。

驅(qū)動包需要安裝:

go get -u github.com/go-sql-driver/mysql

使用前,先要導(dǎo)入mysql的包:

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

上面導(dǎo)入了2個包。第一個是sql包,就是我們調(diào)用操作數(shù)據(jù)庫用的。

第二個是驅(qū)動包,這里前面加了占位符,所以這個包只是引入,但是不使用它。并且如果要操作別的數(shù)據(jù)庫的話,只需要修改驅(qū)動包就行了。

連接數(shù)據(jù)庫

構(gòu)建連接, 格式是:”用戶名:密碼@tcp(IP:端口)/數(shù)據(jù)庫?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("連接數(shù)據(jù)庫失敗:", err)
    return
  }
  DB = database
}

func main() {
  fmt.Println(DB)
  DB.SetMaxIdleConns(16) //設(shè)置閑置連接數(shù)
  DB.SetMaxOpenConns(100) //設(shè)置最大連接數(shù)
  DB.SetConnMaxLifetime(100*time.Second) //最大連接周期,超過時間的連接就close
  fmt.Println(DB)
}


插入數(shù)據(jù)

下面是插入數(shù)據(jù),并且再獲取id的示例:

// 數(shù)據(jù)庫連接的init函數(shù)就省略了
func insert() {
  r, err := DB.Exec("insert into person(username,gender,email) values(?,?,?)", "Barry", "Male", "Barry@go.net")
  if err != nil {
    fmt.Println("插入數(shù)據(jù)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(?,?,?) 里的問號,是占位符,具體的值可以寫在后面的參數(shù)里。當(dāng)然如果不用占位符,直接就傳1個字符串作為參數(shù)也是可以的。

查詢

查詢單個字段:

func query() {
  row := DB.QueryRow("select username from person where user_id=?", 1)
  var name string // 創(chuàng)建變量用于存放查詢到的數(shù)據(jù)
  if err := row.Scan(&name); err != nil {
    fmt.Println("Scan Failed:", err)
    return
  }
  fmt.Println(name)
}

func main() {
  query()
}

也可以一次查詢多個字段或所有字段,查詢之前按照表的類型創(chuàng)建結(jié)構(gòu)體,用查詢到的數(shù)據(jù)為結(jié)構(gòu)體賦值:

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中的字段必須是按照數(shù)據(jù)庫存入字段的順序,否則報錯
  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()
}


數(shù)據(jù)模型,就是上面定義的結(jié)構(gòu)體。這里的類型可以是Go的標(biāo)準(zhǔn)數(shù)據(jù)類型。但是如果數(shù)據(jù)庫的字段允許為空,并且該字段的值也為空,那么查詢后該字段會返回nil。如果是string類型,則無法接收nil,但sql.NullString則可以接收nil值。

另外,結(jié)構(gòu)體里的tag標(biāo)簽在這里沒有意義。不過上面的tag標(biāo)注了該字段在數(shù)據(jù)庫里對應(yīng)的字段名,可能在別處會有用。

查詢多行

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()
}


查詢用起來還是不太方法,不過還可以選擇其他第三方庫,那里會有一些很好的擴(kuò)展。后面會舉例。

其他操作

由于基本都是用SQL的命令進(jìn)行操作,所以其他操作就不一個一個舉例了

update 更新數(shù)據(jù)

result, err := DB.Exec("UPDATE person set email=? where username=?", "Cara", Cara@catco.org)

delete 刪除數(shù)據(jù)

result,err := DB.Exec("DELETE FROM person where id=?",1)

注意:更新數(shù)據(jù)不返回LastInsertID,所以result.LastInsertID一直為0。刪除數(shù)據(jù)可以拿到LastInsertID,用法和插入數(shù)據(jù)里一樣。

第三方庫 sqlx

sqlx是一個go語言包,在內(nèi)置database/sql包之上增加了很多擴(kuò)展,簡化數(shù)據(jù)庫操作代碼的書寫。

由于database/sql接口是sqlx的子集,所有database/sql的用法,在sqlx中一樣可以用。不過sqlx還有更多擴(kuò)展,用起來更方便。

安裝:

go get github.com/jmoiron/sqlx

查詢 Select() 方法

Select是一個非常省時的擴(kuò)展。它們把query和非常靈活的scan語法結(jié)合起來。Select用來獲取結(jié)果切片:

// 這里的tag標(biāo)簽就有意義了,下面的Select()方法應(yīng)該就是根據(jù)tag標(biāo)簽對號入座的
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 // 這里創(chuàng)建的是存放結(jié)構(gòu)體的切片
  if err := DB.Select(&person, "select * from person where userid > ?", 1); err != nil {
    fmt.Println("Select ERROR:", err)
    return
  }
  fmt.Println(person)
}


Select可以提高編碼效率,還有更多擴(kuò)展。sqlx 號稱 golang 數(shù)據(jù)庫開發(fā)神器,這里就提一下,等到真正用的時候再去深入學(xué)習(xí)了。

相關(guān)文章

  • goland安裝1.7版本報錯Unpacked?SDK?is?corrupted解決

    goland安裝1.7版本報錯Unpacked?SDK?is?corrupted解決

    這篇文章主要為大家介紹了goland安裝1.7版本報錯Unpacked?SDK?is?corrupted解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Go設(shè)計模式之代理模式講解和代碼示例

    Go設(shè)計模式之代理模式講解和代碼示例

    這篇文章主要介紹了Go代理模式,代理是一種結(jié)構(gòu)型設(shè)計模式, 讓你能提供真實(shí)服務(wù)對象的替代品給客戶端使用,本文將對Go代理模式進(jìn)行講解以及代碼示例,需要的朋友可以參考下
    2023-07-07
  • 一文介紹Go語言中的指針

    一文介紹Go語言中的指針

    指針是一個存儲變量內(nèi)存地址的變量,本文主要介紹了Go語言中的指針,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • Go語言Gin框架前后端分離項(xiàng)目開發(fā)實(shí)例

    Go語言Gin框架前后端分離項(xiàng)目開發(fā)實(shí)例

    本文主要介紹了Go語言Gin框架前后端分離項(xiàng)目開發(fā)工程化實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-11-11
  • Golang unsafe.Sizeof函數(shù)代碼示例使用解析

    Golang unsafe.Sizeof函數(shù)代碼示例使用解析

    這篇文章主要為大家介紹了Golang unsafe.Sizeof函數(shù)代碼示例使用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Golang編程實(shí)現(xiàn)生成n個從a到b不重復(fù)隨機(jī)數(shù)的方法

    Golang編程實(shí)現(xiàn)生成n個從a到b不重復(fù)隨機(jī)數(shù)的方法

    這篇文章主要介紹了Golang編程實(shí)現(xiàn)生成n個從a到b不重復(fù)隨機(jī)數(shù)的方法,結(jié)合實(shí)例形式分析了Go語言字符串操作及隨機(jī)數(shù)生成的相關(guān)操作技巧,需要的朋友可以參考下
    2017-01-01
  • Go語言-為什么返回值為接口類型,卻返回結(jié)構(gòu)體

    Go語言-為什么返回值為接口類型,卻返回結(jié)構(gòu)體

    這篇文章主要介紹了Go語言返回值為接口類型,卻返回結(jié)構(gòu)體的實(shí)例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • GO中公平鎖和非公平鎖的具體使用

    GO中公平鎖和非公平鎖的具體使用

    公平鎖和非公平鎖是計算機(jī)科學(xué)中的兩種鎖機(jī)制,它們主要用于多線程編程,以控制對共享資源的訪問,本文主要介紹了GO中公平鎖和非公平鎖的具體使用,感興趣的可以了解一下
    2024-08-08
  • 深入理解Golang?Channel?的底層結(jié)構(gòu)

    深入理解Golang?Channel?的底層結(jié)構(gòu)

    這篇文章主要介紹了深入理解Golang?Channel?的底層結(jié)構(gòu),Go?語言的?channel?底層是什么數(shù)據(jù)結(jié)構(gòu)?下面我們就一起來深入解析一下?channel,需要的朋友可以參考下
    2022-01-01
  • 如何理解Go函數(shù)是一等公民原理及使用場景

    如何理解Go函數(shù)是一等公民原理及使用場景

    這篇文章主要為大家介紹了如何理解Go函數(shù)是一等公民及使用場景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07

最新評論

嘉兴市| 文安县| 镶黄旗| 西和县| 定远县| 沽源县| 合川市| 淳化县| 黔东| 介休市| 南昌市| 南郑县| 安西县| 当雄县| 安多县| 东丽区| 泊头市| 棋牌| 宣恩县| 桦甸市| 鄄城县| 湖南省| 榆树市| 台东县| 阿克| 祁门县| 黄山市| 朝阳区| 礼泉县| 泌阳县| 霍林郭勒市| 栾川县| 土默特右旗| 永济市| 旺苍县| 浙江省| 普兰县| 蚌埠市| 同仁县| 舟山市| 互助|