第10天-高级-Web开发与Mysql数据库

本节主要内容:

1. http编程
2. mysql使用
3. 课后作业

1. http编程

(1)http编程分析

  • Go原生支持http,import(“net/http”)
  • Go的http服务性能和nginx比较接近
  • 几行代码就可以实现一个web服务

      关于HTTP,TCP/IP相关知识可以看系列博客 https://www.jianshu.com/p/dfbac2ff2657

      首先来看一个最简单的http服务器:

 1 package main
 2 
 3 import (
 4     "io"
 5     "log"
 6     "net/http"
 7 )
 8 
 9 func main() {
10     // Hello world, the web server
11 
12     helloHandler := func(w http.ResponseWriter, req *http.Request) {
13         io.WriteString(w, "Hello, world!\n")
14     }
15 
16     http.HandleFunc("/hello", helloHandler)
17     log.Fatal(http.ListenAndServe(":8080", nil))
18 }
http server(hello world)

      执行结果:

      几个函数及接口定义:

  • HandleFunc
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

HandleFunc registers the handler function for the given pattern in the DefaultServeMux. The documentation for ServeMux explains how patterns 
are matched.
 1 package main
 2 
 3 import (
 4     "io"
 5     "log"
 6     "net/http"
 7 )
 8 
 9 func main() {
10     h1 := func(w http.ResponseWriter, _ *http.Request) {
11         io.WriteString(w, "Hello from a HandleFunc #1!\n")
12     }
13     h2 := func(w http.ResponseWriter, _ *http.Request) {
14         io.WriteString(w, "Hello from a HandleFunc #2!\n")
15     }
16 
17     http.HandleFunc("/", h1)
18     http.HandleFunc("/endpoint", h2)
19 
20     log.Fatal(http.ListenAndServe(":8080", nil))
21 }
HandleFunc
  • ResponseWriter接口
A ResponseWriter interface is used by an HTTP handler to construct an HTTP response.
A ResponseWriter may not be used after the Handler.ServeHTTP method has returned.
 1 type ResponseWriter interface {
 2         // Header returns the header map that will be sent by
 3         // WriteHeader. The Header map also is the mechanism with which
 4         // Handlers can set HTTP trailers.
 5         //
 6         // Changing the header map after a call to WriteHeader (or
 7         // Write) has no effect unless the modified headers are
 8         // trailers.
 9         //
10         // There are two ways to set Trailers. The preferred way is to
11         // predeclare in the headers which trailers you will later
12         // send by setting the "Trailer" header to the names of the
13         // trailer keys which will come later. In this case, those
14         // keys of the Header map are treated as if they were
15         // trailers. See the example. The second way, for trailer
16         // keys not known to the Handler until after the first Write,
17         // is to prefix the Header map keys with the TrailerPrefix
18         // constant value. See TrailerPrefix.
19         //
20         // To suppress automatic response headers (such as "Date"), set
21         // their value to nil.
22         Header() Header
23 
24         // Write writes the data to the connection as part of an HTTP reply.
25         //
26         // If WriteHeader has not yet been called, Write calls
27         // WriteHeader(http.StatusOK) before writing the data. If the Header
28         // does not contain a Content-Type line, Write adds a Content-Type set
29         // to the result of passing the initial 512 bytes of written data to
30         // DetectContentType. Additionally, if the total size of all written
31         // data is under a few KB and there are no Flush calls, the
32         // Content-Length header is added automatically.
33         //
34         // Depending on the HTTP protocol version and the client, calling
35         // Write or WriteHeader may prevent future reads on the
36         // Request.Body. For HTTP/1.x requests, handlers should read any
37         // needed request body data before writing the response. Once the
38         // headers have been flushed (due to either an explicit Flusher.Flush
39         // call or writing enough data to trigger a flush), the request body
40         // may be unavailable. For HTTP/2 requests, the Go HTTP server permits
41         // handlers to continue to read the request body while concurrently
42         // writing the response. However, such behavior may not be supported
43         // by all HTTP/2 clients. Handlers should read before writing if
44         // possible to maximize compatibility.
45         Write([]byte) (int, error)
46 
47         // WriteHeader sends an HTTP response header with the provided
48         // status code.
49         //
50         // If WriteHeader is not called explicitly, the first call to Write
51         // will trigger an implicit WriteHeader(http.StatusOK).
52         // Thus explicit calls to WriteHeader are mainly used to
53         // send error codes.
54         //
55         // The provided code must be a valid HTTP 1xx-5xx status code.
56         // Only one header may be written. Go does not currently
57         // support sending user-defined 1xx informational headers,
58         // with the exception of 100-continue response header that the
59         // Server sends automatically when the Request.Body is read.
60         WriteHeader(statusCode int)
61 }
type ResponseWriter interface
  •  ListenAndServe
func ListenAndServe(addr string, handler Handler) error
ListenAndServe listens on the TCP network address addr and then calls Serve with handler to handle requests on incoming connections. 
Accepted connections are configured to enable TCP keep
-alives. The handler is typically nil, in which case the DefaultServeMux is used. ListenAndServe always returns a non-nil error.

      具体实现过程需要分析:后续补上。

(2)http常见请求方法
    1)Get请求
    2)Post请求
    3)Put请求
    4)Delete请求
    5)Head请求

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "io/ioutil"
 6     "net/http"
 7 )
 8 
 9 func main() {
10     res, err := http.Get("https://www.baidu.com/")
11     if err != nil {
12         fmt.Println("get err:", err)
13         return
14     }
15 
16     data, err := ioutil.ReadAll(res.Body)
17     if err != nil {
18         fmt.Println("get data err:", err)
19         return
20     }
21 
22     fmt.Println(string(data))
23 }
Get请求示例
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "net/http"
 6 )
 7 
 8 var url = []string{
 9     "http://www.baidu.com",
10     "http://google.com",
11     "http://taobao.com",
12 }
13 
14 func main() {
15 
16     for _, v := range url {
17         resp, err := http.Head(v)
18         if err != nil {
19             fmt.Printf("head %s failed, err:%v\n", v, err)
20             continue
21         }
22 
23         fmt.Printf("head succ, status:%v\n", resp.Status)
24     }
25 }
Head请求示例
  • Get
 1 func (c *Client) Get(url string) (resp *Response, err error)
 2   
 3 Get issues a GET to the specified URL. If the response is one of the following redirect codes, Get follows the redirect after calling the Client's CheckRedirect function:
 4 
 5 301 (Moved Permanently)
 6 302 (Found)
 7 303 (See Other)
 8 307 (Temporary Redirect)
 9 308 (Permanent Redirect)
10 An error is returned if the Client's CheckRedirect function fails or if there was an HTTP protocol error. A non-2xx response doesn't cause an error. Any returned error will be of type *url.Error. The url.Error value's Timeout method will report true if request timed out or was canceled.
11 
12 When err is nil, resp always contains a non-nil resp.Body. Caller should close resp.Body when done reading from it.
13 
14 To make a request with custom headers, use NewRequest and Client.Do.
Get
  • Head
 1 func Head(url string) (resp *Response, err error)
 2 
 3 func (c *Client) Head(url string) (resp *Response, err error)
 4 Head issues a HEAD to the specified URL. If the response is one of the following redirect codes, Head follows the redirect after calling the Client's CheckRedirect function:
 5 
 6 301 (Moved Permanently)
 7 302 (Found)
 8 303 (See Other)
 9 307 (Temporary Redirect)
10 308 (Permanent Redirect)
Head
  • Response
 1 type Response struct {
 2         Status     string // e.g. "200 OK"
 3         StatusCode int    // e.g. 200
 4         Proto      string // e.g. "HTTP/1.0"
 5         ProtoMajor int    // e.g. 1
 6         ProtoMinor int    // e.g. 0
 7 
 8         // Header maps header keys to values. If the response had multiple
 9         // headers with the same key, they may be concatenated, with comma
10         // delimiters.  (RFC 7230, section 3.2.2 requires that multiple headers
11         // be semantically equivalent to a comma-delimited sequence.) When
12         // Header values are duplicated by other fields in this struct (e.g.,
13         // ContentLength, TransferEncoding, Trailer), the field values are
14         // authoritative.
15         //
16         // Keys in the map are canonicalized (see CanonicalHeaderKey).
17         Header Header
18 
19         // Body represents the response body.
20         //
21         // The response body is streamed on demand as the Body field
22         // is read. If the network connection fails or the server
23         // terminates the response, Body.Read calls return an error.
24         //
25         // The http Client and Transport guarantee that Body is always
26         // non-nil, even on responses without a body or responses with
27         // a zero-length body. It is the caller's responsibility to
28         // close Body. The default HTTP client's Transport may not
29         // reuse HTTP/1.x "keep-alive" TCP connections if the Body is
30         // not read to completion and closed.
31         //
32         // The Body is automatically dechunked if the server replied
33         // with a "chunked" Transfer-Encoding.
34         //
35         // As of Go 1.12, the Body will be also implement io.Writer
36         // on a successful "101 Switching Protocols" responses,
37         // as used by WebSockets and HTTP/2's "h2c" mode.
38         Body io.ReadCloser
39 
40         // ContentLength records the length of the associated content. The
41         // value -1 indicates that the length is unknown. Unless Request.Method
42         // is "HEAD", values >= 0 indicate that the given number of bytes may
43         // be read from Body.
44         ContentLength int64
45 
46         // Contains transfer encodings from outer-most to inner-most. Value is
47         // nil, means that "identity" encoding is used.
48         TransferEncoding []string
49 
50         // Close records whether the header directed that the connection be
51         // closed after reading Body. The value is advice for clients: neither
52         // ReadResponse nor Response.Write ever closes a connection.
53         Close bool
54 
55         // Uncompressed reports whether the response was sent compressed but
56         // was decompressed by the http package. When true, reading from
57         // Body yields the uncompressed content instead of the compressed
58         // content actually set from the server, ContentLength is set to -1,
59         // and the "Content-Length" and "Content-Encoding" fields are deleted
60         // from the responseHeader. To get the original response from
61         // the server, set Transport.DisableCompression to true.
62         Uncompressed bool // Go 1.7
63 
64         // Trailer maps trailer keys to values in the same
65         // format as Header.
66         //
67         // The Trailer initially contains only nil values, one for
68         // each key specified in the server's "Trailer" header
69         // value. Those values are not added to Header.
70         //
71         // Trailer must not be accessed concurrently with Read calls
72         // on the Body.
73         //
74         // After Body.Read has returned io.EOF, Trailer will contain
75         // any trailer values sent by the server.
76         Trailer Header
77 
78         // Request is the request that was sent to obtain this Response.
79         // Request's Body is nil (having already been consumed).
80         // This is only populated for Client requests.
81         Request *Request
82 
83         // TLS contains information about the TLS connection on which the
84         // response was received. It is nil for unencrypted responses.
85         // The pointer is shared between responses and should not be
86         // modified.
87         TLS *tls.ConnectionState // Go 1.3
88 }
Response
  •  http 常见状态码
http.StatusContinue = 100
http.StatusOK = 200
http.StatusFound = 302
http.StatusBadRequest = 400
http.StatusUnauthorized = 401
http.StatusForbidden = 403
http.StatusNotFound = 404
http.StatusInternalServerError = 500

(3)表单处理

 1 package main
 2 import (
 3     "io"
 4     "net/http"
 5 )
 6 
 7 const form = `<html><body><form action="#" method="post" name="bar">
 8                     <input type="text" name="in"/>
 9                     <input type="text" name="in"/>
10                      <input type="submit" value="Submit"/>
11              </form></html></body>`
12 
13 func SimpleServer(w http.ResponseWriter, request *http.Request) {
14     io.WriteString(w, "<h1>hello, world</h1>")
15 }
16 
17 func FormServer(w http.ResponseWriter, request *http.Request) {
18     w.Header().Set("Content-Type", "text/html")
19     switch request.Method {
20     case "GET":
21         io.WriteString(w, form)
22     case "POST":
23         request.ParseForm()
24         io.WriteString(w, request.Form["in"][0])
25         io.WriteString(w, "\n")
26         io.WriteString(w, request.FormValue("in"))
27     }
28 }
29 func main() {
30     http.HandleFunc("/test1", SimpleServer)
31     http.HandleFunc("/test2", FormServer)
32     if err := http.ListenAndServe(":8088", nil); err != nil {
33     }
34 }
form表单处理

    执行结果:

    url: test1

 

    url: test2(第一次请求是GET,第二次是POST请求)

    GET请求:

 

    POST请求:

(4)模板

    1)替换 {{.字段名}}

     模板中的点(.)为结构体中的p

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "text/template"
 7 )
 8 
 9 type Person struct {
10     Name string
11     Age  string
12     Title string
13 }
14 
15 func main() {
16     t, err := template.ParseFiles("./index.html")
17     if err != nil {
18         fmt.Println("parse file err:", err)
19         return
20     }
21     p := Person{Name: "Mary", Age: "31", Title:"My blog"}
22     if err := t.Execute(os.Stdout, p); err != nil {
23         fmt.Println("There was an error:", err.Error())
24     }
25 }
template.go
1 <html>
2     <head>
3         <title>{{.Title}}</title>
4     </head>
5     <body>
6         <p> hello, {{.Name}}</p>
7         <p> {{.}}</p>
8     </body>
9 </html>
index.html

    2)if判断

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "text/template"
 7 )
 8 
 9 type Person struct {
10     Name string
11     Age  int
12     Title string
13 }
14 
15 func main() {
16     t, err := template.ParseFiles("./index2.html")
17     if err != nil {
18         fmt.Println("parse file err:", err)
19         return
20     }
21     p := Person{Name: "Mary", Age: 17, Title:"My blog"}
22     if err := t.Execute(os.Stdout, p); err != nil {
23         fmt.Println("There was an error:", err.Error())
24     }
25 }
template2.go
 1 <html>
 2     <head>
 3         <title>{{.Title}}</title>
 4     </head>
 5     <body>
 6         {{if ge .Age 18}}
 7             <p>hello, old man, {{.Name}}</p>
 8         {{else}}
 9             <p>hello,young man, {{.Name}}</p>
10         {{end}}
11     </body>
12 </html>
index2.html
if常见操作符:

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 小于 (less than) {{if lt .var1 .var2}} {{end}}
le 小于等于 {{if le .var1 .var2}} {{end}}
gt 大于 {{if gt .var1 .var2}} {{end}}
ge 大于等于 {{if ge .var1 .var2}} {{end}}

(3)点(.)

{{.}}

<html>
    <head>
    </head>
    <body>
        <p>hello, old man, {{.}}</p>
    </body>
</html>

(4)with

    with语言在Python中可以开启一个上下文环境。对于go模板,with语句类似,其含义就是创建一个封闭的作用域,在其范围内,可以使用.action,而与外面的.无关,只与with的参数有关:

{{ with arg }}
    此时的点 . 就是arg
{{ end }}
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "text/template"
 7 )
 8 
 9 type Person struct {
10     Name string
11     Age  int
12     Title string
13 }
14 
15 func main() {
16     t, err := template.ParseFiles("./index3.html")
17     if err != nil {
18         fmt.Println("parse file err:", err)
19         return
20     }
21     p := Person{Name: "Mary", Age: 17, Title:"My blog"}
22     if err := t.Execute(os.Stdout, p); err != nil {
23         fmt.Println("There was an error:", err.Error())
24     }
25 }
template3.go
 1 <html>
 2     <head>
 3     </head>
 4     <body>
 5         {{with "my with"}}
 6             <p>in: {{.}}</p>
 7         {{end}}
 8         <p>out: {{.}}</p>
 9     </body>
10 </html>
index3.html

    执行结果:

<html>
    <head>
    </head>
    <body>

            <p>in: my with</p>

        <p>out: {Mary 17 My blog}</p>
    </body>
</html>

(5)循环

    {{range.}} ... {{end }}

 1 <html>
 2     <head>
 3     </head>
 4     <body>
 5         {{range .}}
 6             {{if gt .Age 18}}
 7                 <p>hello, old man, {{.Name}}</p>
 8             {{else}}
 9                 <p>hello,young man, {{.Name}}</p>
10             {{end}}
11         {{end}}
12     </body>
13 </html>
index5.html
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "text/template"
 7 )
 8 
 9 type Person struct {
10     Name string
11     Age  int
12     Title string
13 }
14 
15 func main() {
16     t, err := template.ParseFiles("./index5.html")
17     if err != nil {
18         fmt.Println("parse file err:", err)
19         return
20     }
21     
22     p := []Person {
23             Person {
24                 Name: "Mary", 
25                 Age: 17, 
26                 Title:"My blog",
27             },
28             Person {
29                 Name: "Sara", 
30                 Age: 18, 
31                 Title:"My blog",
32             },
33             Person {
34                 Name: "Jack", 
35                 Age: 19, 
36                 Title:"My blog",
37             },
38         }
39 
40     if err := t.Execute(os.Stdout, p); err != nil {
41         fmt.Println("There was an error:", err.Error())
42     }
43 }
template5.go

    执行结果:

<html>
    <head>
    </head>
    <body>
                <p>hello,young man, Mary</p>
                <p>hello,young man, Sara</p>
                <p>hello, old man, Jack</p>
    </body>
</html>

2. mysql使用

(1)连接mysql

    1)安装第三方驱动库

     首先需要安装go驱动mysql数据库的API库:

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

    Golang 提供了database/sql包用于对SQL数据库的访问, 作为操作数据库的入口对象sql.DB, 主要为我们提供了两个重要的功能:

  • sql.DB 通过数据库驱动为我们提供管理底层数据库连接的打开和关闭操作.
  • sql.DB 为我们管理数据库连接池

    需要注意的是,sql.DB表示操作数据库的抽象访问接口,而非一个数据库连接对象;它可以根据driver打开关闭数据库连接,管理连接池。正在使用的连接被标记为繁忙,用完后回到连接池等待下次使用。所以,如果你没有把连接释放回连接池,会导致过多连接使系统资源耗尽。

    sqlx使用指南:

    sqlx是一个go语言包,在内置database/sql包之上增加了很多扩展,简化数据库操作代码的书写。
    由于database/sql接口是sqlx的子集,当前文档中所有关于database/sql的用法同样用于sqlx。

    需要安装下面的API库:

go get github.com/jmoiron/sqlx

    sqlx的详细使用可以看:http://jmoiron.github.io/sqlx/

   2)操作mysql数据库

     首先连接mysql数据库并创建测试数据库及测试表(mysql数据库在Linux Centos6.5上安装):

     创建数据库并切换到创建的数据库中:

mysql> CREATE DATABASE mydb;
Query OK, 1 row affected (0.02 sec)
mysql> USE mydb;
Database changed

     创建测试表:

CREATE TABLE person (
    user_id int primary key auto_increment,
    username varchar(260),
    sex varchar(260),
    email varchar(260)
);

CREATE TABLE place (
    country varchar(200),
    city varchar(200),
    telcode int
);

     导入mysql数据库驱动:

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

     通常来说, 不应该直接使用驱动所提供的方法, 而是应该使用 sql.DB, 因此在导入 mysql 驱动时, 这里使用了匿名导入的方式(在包路径前添加 _), 当导入了一个数据库驱动后, 此驱动会自行初始化并注册自己到Golang的database/sql上下文中, 因此我们就可以通过 database/sql 包提供的方法访问数据库了.

    连接数据库:

const (
    userName = "root"
    password = "root"
    ip = "192.168.30.134"
    port = "3306"
    dbName = "mydb"
)

var Db *sqlx.DB

func init() {
    path := strings.Join([]string{userName, ":", password, "@tcp(",ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
    database, err := sqlx.Open("mysql", path)
    if err != nil {
        fmt.Println("open mysql failed,", err)
        return
    }
    Db = database
}

    我们将连接数据库接口写到init()函数中,在程序刚开始执行时,会先初始化init()函数,然后将结果存储到Db当中。

    通过调用sqlx.Open函数返回一个DB结构体指针; sqlx.Open函数原型如下(对sql.Open做了一层封装):

// Open is the same as sql.Open, but returns an *sqlx.DB instead.
func Open(driverName, dataSourceName string) (*DB, error) {
    db, err := sql.Open(driverName, dataSourceName)
    if err != nil {
        return nil, err
    }
    return &DB{DB: db, driverName: driverName, Mapper: mapper()}, err
}

    driverName: 使用的驱动名. 这个名字其实就是数据库驱动注册到 database/sql 时所使用的名字。
    dataSourceName: 数据库连接信息,这个连接包含了数据库的用户名, 密码, 数据库主机以及需要连接的数据库名等信息。

  • sql.Open并不会立即建立一个数据库的网络连接, 也不会对数据库链接参数的合法性做检验, 它仅仅是初始化一个sql.DB对象. 当真正进行第一次数据库查询操作时, 此时才会真正建立网络连接;
  • sql.DB表示操作数据库的抽象接口的对象,但不是所谓的数据库连接对象,sql.DB对象只有当需要使用时才会创建连接,如果想立即验证连接,需要用Ping()方法;
  • sql.Open返回的sql.DB对象是协程并发安全的.
  • sql.DB的设计就是用来作为长连接使用的。不要频繁Open, Close。比较好的做法是,为每个不同的datastore建一个DB对象,保持这些对象Open。如果需要短连接,那么把DB作为参数传入function,而不要在function中Open, Close。

    上面代码见:github.com\jmoiron\sqlx\sqlx.go,下同。

                         Go操作Mysql更多接口见官网:https://golang.org/pkg/database/sql/

    DB结构体:

// DB is a wrapper around sql.DB which keeps track of the driverName upon Open,
// used mostly to automatically bind named queries using the right bindvars.
type DB struct {
    *sql.DB
    driverName string
    unsafe     bool
    Mapper     *reflectx.Mapper
}
  • insert操作
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "strings"
 6     _ "github.com/go-sql-driver/mysql"
 7     "github.com/jmoiron/sqlx"
 8 )
 9 
10 type Person struct {
11     UserId   int    `db:"user_id"`
12     Username string `db:"username"`
13     Sex      string `db:"sex"`
14     Email    string `db:"email"`
15 }
16 
17 type Place struct {
18     Country string `db:"country"`
19     City    string `db:"city"`
20     TelCode int    `db:"telcode"`
21 }
22 
23 const (
24     userName = "root"
25     password = "root"
26     ip = "192.168.30.134"
27     port = "3306"
28     dbName = "mydb"
29 )
30 
31 var Db *sqlx.DB
32 
33 func init() {
34     path := strings.Join([]string{userName, ":", password, "@tcp(",ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
35     database, err := sqlx.Open("mysql", path)
36     if err != nil {
37         fmt.Println("open mysql failed,", err)
38         return
39     }
40     Db = database
41 }
42 
43 func main() {
44     insert_cmd := `insert into person(username, sex, email)values(?, ?, ?)`
45     r, err := Db.Exec(insert_cmd, "stu002", "femal", "[email protected]")
46     if err != nil {
47         fmt.Println("exec failed, ", err)
48         return
49     }
50 
51     id, err := r.LastInsertId()
52     if err != nil {
53         fmt.Println("exec failed, ", err)
54         return
55     }
56 
57     fmt.Println("insert succ:", id)
58 }
insert
LastInsertId() (int64, error)
// LastInsertId returns the integer generated by the database
// in response to a command. Typically this will be from an
// "auto increment" column when inserting a new row. Not all
// databases support this feature, and the syntax of such
// statements varies.
  • Select 操作
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "strings"
 6     _ "github.com/go-sql-driver/mysql"
 7     "github.com/jmoiron/sqlx"
 8 )
 9 
10 type Person struct {
11     UserId   int    `db:"user_id"`
12     Username string `db:"username"`
13     Sex      string `db:"sex"`
14     Email    string `db:"email"`
15 }
16 
17 type Place struct {
18     Country string `db:"country"`
19     City    string `db:"city"`
20     TelCode int    `db:"telcode"`
21 }
22 
23 const (
24     userName = "root"
25     password = "root"
26     ip = "192.168.30.134"
27     port = "3306"
28     dbName = "mydb"
29 )
30 
31 var Db *sqlx.DB
32 
33 func init() {
34     path := strings.Join([]string{userName, ":", password, "@tcp(",ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
35     database, err := sqlx.Open("mysql", path)
36     if err != nil {
37         fmt.Println("open mysql failed,", err)
38         return
39     }
40     Db = database
41 }
42 
43 func main() {
44 
45     var person []Person
46     select_cmd := `select user_id, username, sex, email from person where user_id=?`
47     err := Db.Select(&person, select_cmd, 1)
48     if err != nil {
49         fmt.Println("exec failed, ", err)
50         return
51     }
52 
53     fmt.Println("select succ:", person)  //select succ: [{1 stu002 femal [email protected]}]
54 }
select
  • update操作
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "strings"
 6     _ "github.com/go-sql-driver/mysql"
 7     "github.com/jmoiron/sqlx"
 8 )
 9 
10 type Person struct {
11     UserId   int    `db:"user_id"`
12     Username string `db:"username"`
13     Sex      string `db:"sex"`
14     Email    string `db:"email"`
15 }
16 
17 type Place struct {
18     Country string `db:"country"`
19     City    string `db:"city"`
20     TelCode int    `db:"telcode"`
21 }
22 
23 const (
24     userName = "root"
25     password = "root"
26     ip = "192.168.30.134"
27     port = "3306"
28     dbName = "mydb"
29 )
30 
31 var Db *sqlx.DB
32 
33 func init() {
34     path := strings.Join([]string{userName, ":", password, "@tcp(",ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
35     database, err := sqlx.Open("mysql", path)
36     if err != nil {
37         fmt.Println("open mysql failed,", err)
38         return
39     }
40     Db = database
41 }
42 
43 func main() {
44     //select
45     var person []Person
46     select_cmd := `select user_id, username, sex, email from person where user_id=?`
47     err := Db.Select(&person, select_cmd, 1)
48     if err != nil {
49         fmt.Println("exec failed, ", err)
50         return
51     }
52     fmt.Println("select succ:", person)  //select succ: [{1 stu001 femal [email protected]}]
53     //update
54     _, err = Db.Exec("update person set username=? where user_id=?", "Jack", 1)
55     if err != nil {
56         fmt.Println("exec failed, ", err)
57         return
58     }
59     //select
60     var person2 []Person
61     err = Db.Select(&person2, "select * from person")
62     if err != nil {
63         fmt.Println("exec failed, ", err)
64         return
65     }
66     fmt.Println("select succ:", person2)  //select succ: [{1 Jack femal [email protected]} {2 stu002 femal [email protected]}]
67 }
update
  • Delete 操作
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "strings"
 6     _ "github.com/go-sql-driver/mysql"
 7     "github.com/jmoiron/sqlx"
 8 )
 9 
10 type Person struct {
11     UserId   int    `db:"user_id"`
12     Username string `db:"username"`
13     Sex      string `db:"sex"`
14     Email    string `db:"email"`
15 }
16 
17 type Place struct {
18     Country string `db:"country"`
19     City    string `db:"city"`
20     TelCode int    `db:"telcode"`
21 }
22 
23 const (
24     userName = "root"
25     password = "root"
26     ip = "192.168.30.134"
27     port = "3306"
28     dbName = "mydb"
29 )
30 
31 var Db *sqlx.DB
32 
33 func init() {
34     path := strings.Join([]string{userName, ":", password, "@tcp(",ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
35     database, err := sqlx.Open("mysql", path)
36     if err != nil {
37         fmt.Println("open mysql failed,", err)
38         return
39     }
40     Db = database
41 }
42 
43 func main() {
44     //select
45     var person []Person
46     err := Db.Select(&person, "select * from person")
47     if err != nil {
48         fmt.Println("exec failed, ", err)
49         return
50     }
51     fmt.Println("select succ:", person)  //select succ: [{1 Jack femal [email protected]} {2 stu002 femal [email protected]}]
52     //delete
53     _, err = Db.Exec("delete from person where user_id=?", 1)
54     if err != nil {
55         fmt.Println("exec failed, ", err)
56         return
57     }
58     fmt.Println("delete succ")
59     //select
60     var person2 []Person
61     err = Db.Select(&person2, "select * from person")
62     if err != nil {
63         fmt.Println("exec failed, ", err)
64         return
65     }
66     fmt.Println("select succ:", person2)  //select succ: [{2 stu002 femal [email protected]}]
67 }
delete
  • 事物
tx, err := db.Begin()
err = tx.Exec(...)
err = tx.Commit()
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "strings"
 6     _ "github.com/go-sql-driver/mysql"
 7     "github.com/jmoiron/sqlx"
 8 )
 9 
10 type Person struct {
11     UserId   int    `db:"user_id"`
12     Username string `db:"username"`
13     Sex      string `db:"sex"`
14     Email    string `db:"email"`
15 }
16 
17 type Place struct {
18     Country string `db:"country"`
19     City    string `db:"city"`
20     TelCode int    `db:"telcode"`
21 }
22 
23 const (
24     userName = "root"
25     password = "root"
26     ip = "192.168.30.134"
27     port = "3306"
28     dbName = "mydb"
29 )
30 
31 var Db *sqlx.DB
32 
33 func init() {
34     path := strings.Join([]string{userName, ":", password, "@tcp(",ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
35     database, err := sqlx.Open("mysql", path)
36     if err != nil {
37         fmt.Println("open mysql failed,", err)
38         return
39     }
40     Db = database
41 }
42 
43 func main() {
44     //select
45     var person []Person
46     err := Db.Select(&person, "select * from person")
47     if err != nil {
48         fmt.Println("exec failed, ", err)
49         return
50     }
51     fmt.Println("select succ:", person)  //select succ: [{2 stu002 femal [email protected]}]
52     //begin transactions
53     tx, err := Db.Begin()
54     if err != nil {
55         fmt.Println("Failed to begin transactions")
56         return
57     }
58     //insert
59     insert_cmd := `insert into person(username, sex, email)values(?, ?, ?)`
60     r, err := tx.Exec(insert_cmd, "stu008", "man", "[email protected]")
61     if err != nil {
62         fmt.Println("exec failed, ", err)
63         // Rollback
64         if rollbackErr := tx.Rollback(); rollbackErr != nil {
65             fmt.Println("update drivers: unable to rollback: %v", rollbackErr)
66         }
67         return
68     }
69     id, err := r.LastInsertId()
70     if err != nil {
71         fmt.Println("exec failed, ", err)
72         return
73     }
74     fmt.Println("insert succ:", id)  //insert succ: 3
75     //Commit
76     err = tx.Commit()
77     if err != nil {
78         fmt.Println("Failed to commit. Err: ", err)
79         return
80     }
81     //select
82     var person2 []Person
83     err = Db.Select(&person2, "select * from person")
84     if err != nil {
85         fmt.Println("exec failed, ", err)
86         return
87     }
88     fmt.Println("select succ:", person2)  //select succ: [{2 stu002 femal [email protected]} {3 Sara femal [email protected]}]
89 }
transactions

    注意:上面只是介绍了Go操作数据库的基本操作,更加详细的需要看: http://jmoiron.github.io/sqlx/

3. 课后作业

   修改聊天室程序,把数据存储部分切换到mysql中。

4. 参考文献

  • https://www.cnblogs.com/hanyouchun/p/6708037.html
  • https://www.2cto.com/database/201802/721140.html
  • https://blog.csdn.net/wdy_yx/article/details/78262528
  • http://jmoiron.github.io/sqlx/

猜你喜欢

转载自www.cnblogs.com/xuejiale/p/10498661.html
今日推荐