大橙子网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
创建es.go文件
创新互联建站专注于修水企业网站建设,响应式网站,商城网站定制开发。修水网站建设公司,为修水等地区提供建站服务。全流程定制设计,专业设计,全程项目跟踪,创新互联建站专业和态度为您提供的服务
根据elasticsearch版本拉取对应的go包: github.com/elastic/go-elasticsearch
API文档:
Index 在索引中创建或更新文档
索引不存在的情况下,会自动创建索引。
默认的_type(类型)是_doc,下面是指定doc类型创建添加的。
Search 搜索
DeleteByQuery 通过匹配条件删除文档
Delete通过_id删除文档
Create 添加文档(需要指定_id,_id已存在返回409)
Get 通过id获取文档
Update 通过_id更新文档
UpdateByQuery 通过匹配条件更新文档
• 何为框架:
框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用,甚至有的时候,脱离了框架,一些开发者都不会写程序了。成长总不会一蹴而就,从写出程序获取成就感,再到精通框架,快速构造应用,当这些方面都得心应手的时候,可以尝试改造一些框架,或是自己创造一个。
Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,已经发布了1.0版本。具有快速灵活,容错方便等特点。其实对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。
(1)首先需要安装,安装比较简单,使用go get即可
go get github.com/gin-gonic/gin
如果安装失败,直接去Github clone下来,放置到对应的目录即可。
(2)代码中使用:
下面是一个使用Gin的简单例子:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
router.Run(":8080") // listen and serve on 0.0.0.0:8080
}
简单几行代码,就能实现一个web服务。使用gin的Default方法创建一个路由handler。然后通过HTTP方法绑定路由规则和路由函数。不同于net/http库的路由函数,gin进行了封装,把request和response都封装到gin.Context的上下文环境。最后是启动路由的Run方法监听端口。麻雀虽小,五脏俱全。当然,除了GET方法,gin也支持POST,PUT,DELETE,OPTION等常用的restful方法。
Gin可以很方便的支持各种HTTP请求方法以及返回各种类型的数据,详情可以前往查看。
2.1 匹配参数
我们可以使用Gin框架快速的匹配参数,如下代码所示:
冒号:加上一个参数名组成路由参数。可以使用c.Param的方法读取其值。当然这个值是字串string。诸如/user/rsj217,和/user/hello都可以匹配,而/user/和/user/rsj217/不会被匹配。
浏览器输入以下测试:
返回结果为:
其中c.String是gin.Context下提供的方法,用来返回字符串。
其中c.Json是gin.Context下提供的方法,用来返回Json。
下面我们使用以下gin提供的Group函数,方便的为不同的API进行分类。
我们创建了一个gin的默认路由,并为其分配了一个组 v1,监听hello请求并将其路由到视图函数HelloPage,最后绑定到 0.0.0.0:8000
C.JSON是Gin实现的返回json数据的内置方法,包含了2个参数,状态码和返回的内容。http.StatusOK代表返回状态码为200,正文为{"message": “welcome"}。
注:Gin还包含更多的返回方法如c.String, c.HTML, c.XML等,请自行了解。可以方便的返回HTML数据
我们在之前的组v1路由下新定义一个路由:
下面我们访问
可以看到,通过c.Param(“key”)方法,Gin成功捕获了url请求路径中的参数。同理,gin也可以捕获常规参数,如下代码所示:
在浏览器输入以下代码:
通过c.Query(“key”)可以成功接收到url参数,c.DefaultQuery在参数不存在的情况下,会由其默认值代替。
我们还可以为Gin定义一些默认路由:
这时候,我们访问一个不存在的页面:
返回如下所示:
下面我们测试在Gin里面使用Post
在测试端输入:
附带发送的数据,测试即可。记住需要使用POST方法.
继续修改,将PostHandler的函数修改如下
测试工具输入:
发送的内容输入:
返回结果如下:
备注:此处需要指定Content-Type为application/x-www-form-urlencoded,否则识别不出来。
一定要选择对应的PUT或者DELETE方法。
Gin框架快速的创建路由
能够方便的创建分组
支持url正则表达式
支持参数查找(c.Param c.Query c.PostForm)
请求方法精准匹配
支持404处理
快速的返回给客户端数据,常用的c.String c.JSON c.Data
ORM-Object-Relationl Mapping,即对象关系映射,这里的Relationl指的是关系型数据库
它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了
GORM就是go语言实现的一个ORM库
特点:
增加(Create)
检索(Retrieve)
更新(Update)
删除(Delete)
如果模型中有 DeletedAt 字段,它将自动拥有软删除的能力!当执行删除操作时,数据并不会永久的从数据库中删除,而是将 DeletedAt 的值更新为当前时间。
具体的使用可查看gorm 官方文档
在项目中我们定义一个全局的GVA_DB,方便使用时调用
后续我们在需要查询数据库时便可直接通过global.GVA_DB使用
比如创建商品信息:
我们先通过查询分类是否存在,然后再创建商品
通过gorm的链式操作可以很方便的进行crud操作
分页查询是项目中经常使用到的功能,当指定条件查询的数据量过大时,如果我们将数据一次性返回,会对数据库造成较大的负荷,同时降低接口的性能,通常我们会使用分页查询的方式让数据进行分段展示,从而保障接口的性能。在gorm中我们实用Offset,和Count来实现分页
我们通过前端的传递过来的分页数据进行查询
该商城作为gin的学习项目,没有很复杂的逻辑,所有业务逻辑均通过Mysql实现。包括后面将要介绍的登录态,也是如此。
所有代码已上传github,有兴趣的可以访问,如果有更好的建议也欢迎提交issure,pr
不会释放value,仅仅标记为不可用,但实际内存还是在占用
package main
import (
"log"
"runtime"
)
var intMap map[int]int
var cnt = 8192
func main() {
printMemStats()
initMap()
runtime.GC()
printMemStats()
log.Println(len(intMap))
for i := 0; i cnt; i++ {
delete(intMap, i)
}
log.Println(len(intMap))
runtime.GC()
printMemStats()
intMap = nil
runtime.GC()
printMemStats()
}
func initMap() {
intMap = make(map[int]int, cnt)
for i := 0; i cnt; i++ {
intMap[i] = i
}
}
func printMemStats() {
var m runtime.MemStats
runtime.ReadMemStats(m)
log.Printf("Alloc = %v TotalAlloc = %v Sys = %v NumGC = %v\n", m.Alloc/1024, m.TotalAlloc/1024, m.Sys/1024, m.NumGC)
}
sync.Map是1.9才推荐的并发安全的map,除了互斥量以外,还运用了原子操作,所以在这之前,有必要了解下 Go语言——原子操作
go1.10\src\sync\map.go
entry分为三种情况:
从read中读取key,如果key存在就tryStore。
注意这里开始需要加锁,因为需要操作dirty。
条目在read中,首先取消标记,然后将条目保存到dirty里。(因为标记的数据不在dirty里)
最后原子保存value到条目里面,这里注意read和dirty都有条目。
总结一下Store:
这里可以看到dirty保存了数据的修改,除非可以直接原子更新read,继续保持read clean。
有了之前的经验,可以猜测下load流程:
与猜测的 区别 :
由于数据保存两份,所以删除考虑:
先看第二种情况。加锁直接删除dirty数据。思考下貌似没什么问题,本身就是脏数据。
第一种和第三种情况唯一的区别就是条目是否被标记。标记代表删除,所以直接返回。否则CAS操作置为nil。这里总感觉少点什么,因为条目其实还是存在的,虽然指针nil。
看了一圈貌似没找到标记的逻辑,因为删除只是将他变成nil。
之前以为这个逻辑就是简单的将为标记的条目拷贝给dirty,现在看来大有文章。
p == nil,说明条目已经被delete了,CAS将他置为标记删除。然后这个条目就不会保存在dirty里面。
这里其实就跟miss逻辑串起来了,因为miss达到阈值之后,dirty会全量变成read,也就是说标记删除在这一步最终删除。这个还是很巧妙的。
真正的删除逻辑:
很绕。。。。