Go上手--工程实践-新增发布帖子功能 | 青训营笔记

166 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记。 课程内容相关代码链接 取V0版本 我是直接fork到自己Github,然后进行版本切换和修改

一、Git命令熟悉

运行该命令即可克隆代码
(如果只想保留最新的文件而不要历史版本的文件,可以用git pull --dpeth 1命令,即“浅克隆”:) git clone -b v5.2.0 --depth=1 https://github.com/Moonlight-Zhao/go-project-example/
创建新分支命令:git branch xxx
切换分支命令:git checkout xxx
查看当前分支:git branch
想提交代码到自己的Github仓库上时:
git add *
git commit -m "commit"
git push origin xxx (xxx为目标的分支名)

二、实现新功能

我的Github代码:github.com/yhmain/go-p… 项目整体架构:

cedd6c1e71611846cc2c1ea1179e7c4.png

1. Postman测试工具(谷歌浏览器插件)

为了模拟post请求调试
界面截图如下: image.png

2. 本地ID生成需要保证不重复、唯一性

雪花ID:snowflake是Twitter开源的分布式ID生成算法,结果是64bit的Long类型的ID,有着全局唯一和有序递增的特点,利用时间戳生成。
在service层导入包:idworker "github.com/gitstliu/go-id-worker"
基于SnowFlake算法,跨数据中心的全局分布式ID生成器。
应用代码如下: 注意init是个很特殊的函数,用于package的初始化,先于main函数自动执行

var idGen *idworker.IdWorker
//ID生成器的初始化
func init() {
	idGen = &idworker.IdWorker{}
        //WORKERID位数 (用于对工作进程进行编码)
        //数据中心ID位数 (用于对数据中心进行编码)
	idGen.InitIdWorker(1, 1) 
}

func xxx(){
        ...
        id, err := idGen.NextId() //生成新ID
        ...
}

3. Append文件,更新索引,注意 Map 的并发安全问题

sync包实现了两种锁:

  • Mutex:互斥锁
  • RWMutex:读写锁,RWMutex 基于Mutex实现

Mutex

  • 在一个 goroutine 获得 Mutex 后,其他 goroutine 只能等到这个 goroutine 释放该 Mutex
  • 适用于读写不确定,并且只有一个读或者写的场景

RWMutex

  • 锁占用的情况下会阻止写,不会阻止读,多个 goroutine 可以同时获取读锁
  • 写锁会阻止其他 goroutine(无论读和写)进来,整个锁由该 goroutine 独占
  • 适用于读多写少的场景

这里我采用的是读写锁,代码如下:

//向文件/数据库中插入新发布的帖子
func (*PostDao) InsertNewPost(post *Post) error {
	//0600 0rw-------
	open, err := os.OpenFile("./data/post", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		return err
	}
	defer open.Close()
	postStr, _ := json.Marshal(post) //序列号为json格式
	//写入文件时需要string
	//注意windows中回车换行符
	if _, err = open.WriteString(string(postStr) + "\n"); err != nil {
		return err
	}
	//更新Map时考虑并发安全性问题
	rwMutex.Lock()
	postList, ok := postIndexMap[post.ParentId]
	//若字典中不存在该主题ID,则新建
	if !ok {
		postIndexMap[post.ParentId] = []*Post{post}
	} else {
		postList = append(postList, post)
		postIndexMap[post.ParentId] = postList
	}
	rwMutex.Unlock()
	return nil
}

三、测试

  • 单元测试
  • Mock测试
  • 基准测试