《Go Web编程》学习笔记

3.3.6

高效的轻量级第三方多路复用器:HttpRouter

6.3 Go与SQL

修改postgres数据库的用户密码

ALTER USER gwp WITH PASSWORD 'gwp';

使用MySQL(原书使用的是PostgreSQL)

1. 下载驱动 go get github.com/go-sql-driver/mysql

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

// A DSN in its fullest form
username:password@protocol(address)/dbname?param=value

db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/gwp?charset=utf8")

2. 创建表

CREATE TABLE `posts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `content` varchar(1000) CHARACTER SET utf8 DEFAULT NULL,
  `author` varchar(200) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='帖子'

3. mysql_store.go

package main

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

	"fmt"
	"log"
)

type Post struct {
	Id      int
	Content string
	Author  string
}

var Db *sql.DB

// connect to the Db
func init() {
	var err error
	Db, err = sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/gwp?charset=utf8")
	if err != nil {
		panic(err)
	}
}

// get all posts
func Posts(start int, size int) (posts []Post, err error) {
	rows, err := Db.Query("select id, content, author from posts limit ?, ?", start, size)
	defer rows.Close()

	if err != nil {
		return
	}
	for rows.Next() {
		post := Post{}
		err = rows.Scan(&post.Id, &post.Content, &post.Author)
		if err != nil {
			return
		}
		posts = append(posts, post)
	}

	return
}

// Get a single post
func GetPost(id int64) (post Post, err error) {
	post = Post{}
	err = Db.QueryRow("select id, content, author from posts where id = ?", id).Scan(&post.Id, &post.Content, &post.Author)
	return
}

// Create a new post
func (post *Post) Create() (id int64, err error) {
	statement := "insert into posts (content, author) values (?, ?)"
	stmt, err := Db.Prepare(statement)
	if err != nil {
		return
	}

	//res, err := stmt.Exec(post.Content, post.Author)
	res, err := stmt.Exec("李雷爱吃雪糕", "李雷")
	defer stmt.Close()

	id, err = res.LastInsertId()

	return
}

// Update a post
func (post *Post) Update() (err error) {
	_, err = Db.Exec("update posts set content = ?, author = ? where id = ?", post.Content, post.Author, post.Id)
	return
}

// Delete a post
func (post *Post) Delete() (err error) {
	_, err = Db.Exec("delete from posts where id = ?", post.Id)
	return
}

// Delete all posts
func DeleteAll() (err error) {
	_, err = Db.Exec("delete from posts")
	return
}

func main() {
	post := Post{Content: "李雷和韩梅梅", Author: "李雷"}

	// Create a post
	fmt.Println("准备添加:", post) // {0 Hello World! Sau Sheong}
	id, err := post.Create()
	if err != nil {
		log.Fatalln(err)
	}

	// Get one post
	readPost, _ := GetPost(id)
	fmt.Println("根据id获得帖子:", readPost) // {1 Hello World! Sau Sheong}

	// Update the post
	readPost.Content = "Bonjour Monde!"
	readPost.Author = "Pierre"
	readPost.Update()

	posts, _ := Posts(0, 10)
	fmt.Println(posts)

	/*// Get all posts
	posts, _ := Posts(10)
	fmt.Println(posts)

    // Delete the post
	readPost.Delete()

	// Get all posts
	posts, _ = Posts(10)
	fmt.Println(posts) // []*/

	// Delete all posts
	// DeleteAll()

}

6.5 Go与关系映射器

  • Gorm
  • Beego的ORM库以及GORP
  • 如果写web程序的话 用 go-macaron(朋友推荐)
  • Gogs使用go-macaron开发

7.1 Web服务简介

  • REST 速度快并且构建简单;数据驱动。
  • SOAP 安全并且健壮;功能驱动;不仅笨重,而且过于复杂。

7.3 基于REST的Web服务简介

  • WADL、Swagger、RAML(Restful API Modeling Language,REST风格API建模语言)、JSON-home。

7.5.1 分析JSON

  • 如果JSON数据来源于io.Reader流,如http.Request的Body,那么使用Decoder更好;
  • 如果JSON数据来源于字符串或者内存的某个地方,那么使用Unmarshal更好。

8.2 使用Go进行单元测试

  • 使用具体(verbose)标识-v来获得更详细的信息,并通过覆盖率标识-cover来获知测试用例对代码的覆盖率
go test -v -cover

8.2.1 跳过测试用例

// Long running test case
func TestLongRunningTest(t *testing.T) {
  if testing.Short() {
    t.Skip("Skipping long running test in short mode")
  }
  time.Sleep(10 * time.Second)
}
go test -short

8.2.2 以并行方式运行测试

parallel_test.go

package main

import (
	"testing"
	"time"
)

func TestParallel_1(t *testing.T) {
	t.Parallel()
	time.Sleep(1 * time.Second)
}

func TestParallel_2(t *testing.T) {
	t.Parallel()
	time.Sleep(2 * time.Second)
}

func TestParallel_3(t *testing.T) {
	t.Parallel()
	time.Sleep(3 * time.Second)
}
go test -parallel 3

8.2.3 基准测试

基准测试用例也需要放置到以_test.go为后缀的文件中,并且每个基准测试函数都需要符合以下格式

func BenchmarkXxx(*testing.B) {...}
package main

import (
  "testing"
)

func BenchmarkDecode(b *testing.B) {
  for i := 0; i < b.N; i++ {
    decode("post.json") 
  }
}

func BenchmarkUnmarshal(b *testing.B) {
  for i := 0; i < b.N; i++ {
    unmarshal("post.json")
  }
}
// -bench后使用一个正则表达式用作该标志的参数,从而标识出自己想要运行的基准测试文件。
// 当我们需要运行目录下的所有基准测试文件是,只需要把.用作-bench标志的参数即可
go test -v -cover -short -bench .
// 用户可以通过-run来忽略功能测试
// -run标志用于指定需要被执行的功能测试用例,如果用户把一个不存在的功能测试名字用作-run标志的参数,
// 那么所有功能测试都将被忽略。
// x是不存在的功能测试用例
go test -run x -bench .

8.5 第三方Go测试库

  • Gocheck较为简单,整合并扩展了testing包;
  • Ginkgo能够让用户在Go中实现行为驱动开发,但是这个库比较复杂,而且学习曲线也比较陡峭。
发布了182 篇原创文章 · 获赞 42 · 访问量 59万+

猜你喜欢

转载自blog.csdn.net/wyyl1/article/details/81288525