Go 语言开发设计指北
IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《Go 语言开发设计指北》,聊聊MySQL、Redis、go,我们一起来看看吧!
友情提示:此篇文章大约需要阅读 20分钟33秒,不足之处请多指教,感谢你的阅读。 订阅本站
此文章首发于 Debug客栈 |https://www.debuginn.cn
Go 语言是一种强类型、编译型的语言,在开发过程中,代码规范是尤为重要的,一个小小的失误可能会带来严重的事故,拥有一个良好的 Go 语言开发习惯是尤为重要的,遵守开发规范便于维护、便于阅读理解和增加系统的健壮性。
以下是我们项目组开发规范加上自己开发遇到的问题及补充,希望对你有所帮助:
注:我们将以下约束分为三个等级,分别是:【强制】、【推荐】、【参考】。
Go 编码相关
【强制】代码风格规范遵循 go 官方标准:CodeReviewComments,请使用官方golint lint 进行风格静态分析;
【强制】代码格式规范依照
func crond() {
defer func() {
if err := recover(); err != nil {
// dump stack & log
}
}()
// do something
}
func main() {
// init system
go crond()
go crond2()
// handlers
} 【强制】异步开启
func globalCrond() {
for _ := ticker.C {
projectCrond()
itemCrond()
userCrond()
}
}
func projectCrond() {
defer func() {
if err := recover(); err != nil {
// 打日志,并预警
}
}
// do
}【强制】当有并发读写
resp, err := package1.GetUserInfo(xxxxx) // 在err == nil 情况下,resp不能为nil或者空值
【强制】当操作有多个层级的结构体时,基于防御性编程的原则,需要对每个层级做空指针或者空数据判别,特别是在处理复杂的页面结构时,如:
type Section struct {
Item *SectionItem
Height int64
Width int64
}
type SectionItem struct {
Tag string
Icon string
ImageURL string
ImageList []string
Action *SectionAction
}
type SectionAction struct {
Type string
Path string
Extra string
}
func getSectionActionPath(section *Section) (path string, img string, err error) {
if section.Item == nil || section.Item.Action == nil { // 要做好足够防御,避免因为空指针导致的panic
err = fmt.Errorf("section item is invalid")
return
}
path = section.Item.Action.Path
img = section.Item.ImageURL
// 对取数组的内容,也一定加上防御性判断
if len(section.Item.ImageList) > 0 {
img = section.Item.ImageList[0]
}
return
}【推荐】生命期在函数内的资源对象,如果函数逻辑较为复杂,建议使用
func MakeProject() {
conn := pool.Get()
defer pool.Put(conn)
// 业务逻辑
...
return
}对于生命期在函数内的对象,定义在函数内,将使用栈空间,减少
func MakeProject() (project *Project){
project := &Project{} // 使用堆空间
var tempProject Project // 使用栈空间
return
}【强制】不能在循环里加
// 反例:
for {
row, err := db.Query("SELECT ...")
if err != nil {
...
}
defer row.Close() // 这个操作会导致循环里积攒许多临时资源无法释放
...
}
// 正确的处理,可以在循环结束时直接close资源,如果处理逻辑较复杂,可以打包成函数:
for {
func () {
row, err := db.Query("SELECT ...")
if err != nil {
...
}
defer row.Close()
...
}()
}【推荐】对于可预见容量的
headList := make([]home.Sections, 0, len(srcHomeSection)/2) tailList := make([]home.Sections, 0, len(srcHomeSection)/2)
dstHomeSection = make([]*home.Sections, 0, len(srcHomeSection))
….
if appendToHead {
headList = append(headList, info)
} else {
tailList = append(tailList, info)
}
….
dstHomeSection = append(dstHomeSection, headList…)
dstHomeSection = append(dstHomeSection, tailList…)【推荐】逻辑操作中涉及到频繁拼接字符串的代码,请使用
// 正例:
var buf bytes.Buffer
for _, name := range userList {
buf.WriteString(name)
buf.WriteString(",")
}
return buf.String()
// 反例:
var result string
for _, name := range userList {
result += name + ","
}
return result【强制】对于固定的正则表达式,可以在全局变量初始化时完成预编译,可以有效加快匹配速度,不需要在每次函数请求中预编译:
var wordReg = regexp.MustCompile("[w]+")
func matchWord(word string) bool {
return wordReg.MatchString(word)
}【推荐】JSON 解析时,遇到不确定是什么结构的字段,建议使用
// 业务名.服务名.模块.功能.方法 service.gateway.module.action.func
【强制】打点使用场景是监控系统的实时状态,不适合存储任何业务数据;
【强制】在打点个数太多时,展示时速度会变慢。建议单个服务打点的key不超过10000个,
log.Debug("get home page failed %s, id %d", err, id)【强制】如果是解析
value, err := c.RedisCache.GetGzip(key) …. c.RedisCache.SetExGzip(content, 60)
【推荐】Redis 的分布式锁,可以使用:
lock: redis.Do("SET", lockKey, randint, "EX", expire, "NX")
unlock: redis.GetAndDel(lockKey, randint) // redis暂不支持,可以用lua脚本【推荐】尽量避免在逻辑循环代码中调用 Redis,会产生流量放大效应,请求量较大时需采用其他方法优化(比如静态配置文件);
【推荐】
key := "demoid:3344"
value := localcacche.Get(key)
if value == "" {
value = rediscache.Get(key)
if value != "" {
// 随机缓存 1~5s,各个机器间错开峰值,只要比 redis缓存短即可
localcache.SetEx(key, value, rand.Int63n(5)+1)
}
}
if value == "" {
....
// 从其他系统或者数据库获取数据
appoint.GetValue()
// 同时设置到redis及localcache中
rediscache.SetEx(key, content, 60)
localcache.SetEx(key, content, rand.Int63n(5)+1)
}【参考】对于请求量高,实时性也高的内容,如果纯粹使用缓存,当缓存失效瞬间,会导致大量请求穿透到后端服务,导致后端服务有雪崩危险:
如何兼顾扛峰值,保护后端系统,同时也能保持实时性呢?在这种场景下,可以采用随机更新法更新数据,方法如下:
- 正常请求从缓存中读取,缓存失效则从后端服务获取;
- 在请求中根据随机概率1%(或者根据实际业务场景设置比率)会跳过读取缓存操作,直接从后端服务获取数据,并更新缓存。
这种做法能保证最低时效性,并且当访问量越大,更新概率越高,使得内容实时性也越高。
如果结合上一条
-- 字段区分度 item_id > project_id alter table xxx add index idx_item_project (item_id, project_id)
【强制】所有数据库表必须有主键 id;
【强制】主键索引名为 pk字段名; 唯一索引名为 uk字段名; 普通索引名则为 idx_字段名;
【强制】防止因字段类型不同造成的隐式转换,导致索引失效,造成全表扫描问题;
【强制】业务上有唯一特性的字段,即使是多字段的组合,也必须建成唯一索引;
【强制】一般事务标准操作流程:
func TestTXExample(t *testing.T) {
// 打开事务
tx, err := db.Beginx()
if err != nil {
log.Fatal("%v", err)
return
}
// defer异常
needRollback := true
defer func() {
if r := recover(); r != nil { // 处理recover,避免因为panic,资源无法释放
log.Fatal("%v", r)
needRollback = true
}
if needRollback {
xlog.Cause("test.example.transaction.rollback").Fatal()
tx.Rollback()
}
}()
// 事务的逻辑
err = InsertLog(tx, GenTestData(1)[0])
if err != nil {
log.Fatal("%v", err)
return
}
// 提交事务
err = tx.Commit()
if err != nil {
log.Fatal("%v", err)
return
}
needRollback = false
return
}【强制】执行事务操作时,请确保
SELECT ... FOR UPDATE条件命中索引,使用行锁,避免一个事务锁全表的情况;
【强制】禁止超过三个表的
join,需要
join的字段,数据类型必须一致,多表关联查询时,保证被关联的字段有索引;
【强制】数据库
max_open连接数不可设置过高,会导致代理连接数打满导致不可用状况;
今天带大家了解了MySQL、Redis、go的相关知识,希望对你有所帮助;关于数据库的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~
SpringBoot数据库配置问题解析
- 上一篇
- SpringBoot数据库配置问题解析
- 下一篇
- count(*)这么慢,我该怎么办?
-
- 笑点低的宝马
- 感谢大佬分享,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢师傅分享技术文章!
- 2023-03-19 18:19:12
-
- 美好的煎蛋
- 这篇技术贴太及时了,太详细了,真优秀,收藏了,关注up主了!希望up主能多写数据库相关的文章。
- 2023-02-19 15:42:28
-
- 多情的唇膏
- 这篇文章出现的刚刚好,好细啊,赞 ??,已加入收藏夹了,关注博主了!希望博主能多写数据库相关的文章。
- 2023-02-12 23:09:21
-
- 粗犷的金针菇
- 很详细,码住,感谢大佬的这篇技术贴,我会继续支持!
- 2023-02-02 03:50:35
-
- 数据库 · MySQL | 4小时前 |
- MySQL 事件调度器怎样安全执行周期任务
- 159浏览 收藏
-
- 数据库 · MySQL | 4小时前 |
- MySQL histogram 怎样辅助没有合适索引的列估算
- 386浏览 收藏
-
- 数据库 · MySQL | 4小时前 |
- MySQL 死锁日志怎样对应到具体事务
- 185浏览 收藏
-
- 数据库 · MySQL | 4小时前 | MySQL · SQL · mysql ROW_NUMBER 多表UPDATE 关联重复
- MySQL 多表 UPDATE 怎样避免关联重复更新
- 342浏览 收藏
-
- 数据库 · MySQL | 4小时前 |
- MySQL 分区表怎样确认查询命中了分区裁剪
- 347浏览 收藏
-
- 数据库 · MySQL | 4小时前 | MySQL · JSON · 数据库 · 查询优化 · mysql 索引 explain JSON json_extract 生成列 JSON_VALUE JSON_UNQUOTE
- MySQL 生成列怎样把 JSON 路径变成可索引字段
- 475浏览 收藏
-
- 数据库 · MySQL | 4小时前 |
- MySQL GROUP_CONCAT 怎样避免结果被 group_concat_max_len 截断
- 443浏览 收藏
-
- 数据库 · MySQL | 4小时前 |
- MySQL schema_index_statistics 怎样找出读取延迟最高的索引
- 372浏览 收藏
-
- 数据库 · MySQL | 4小时前 |
- MySQL 索引条件下推怎样从执行计划确认
- 188浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 697次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 707次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 777次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 738次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 571次使用
-
- MySQL 明明加了索引,为什么查询还是很慢?先查这 6 个点
- 2026-06-27 374浏览
-
- Go map 并发写 panic 怎么办:从共享 map 到可控写入路径
- 2026-06-30 123浏览
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- Go与Redis实现分布式互斥锁和红锁
- 2022-12-22 117浏览
-
- golang 基于 mysql 简单实现分布式读写锁
- 2023-01-07 384浏览

