基于内存存储实现数据增删改查功能


memory-vs-storage.png

在 Web 编程中,经常需要处理用户请求数据,而用户请求数据的处理往往又涉及到数据存储与获取,支持存储数据的媒介很多,包括内存、文件系统、数据库等,接下来,学院君将花几个篇幅的教程来系统介绍 Go Web 编程中的数据存储与获取。

首先我们来看内存存储。

相较于磁盘文件和数据库,内存存取性能与效率是最高的,但是价格也是高昂的,这就导致内存存储空间有限;另外,内存数据不能持久化存储,如果系统断电或者异常重启,那么存储在内存中的数据都会消失。

因此,我们通常可以将当前运行程序需要处理的数据临时存放到内存中,以便提高程序性能,处理完成后持久化到磁盘(关系型数据库最终也是将数据存储到磁盘文件)中,从而充分利用内存的高性能和磁盘的大空间和数据可持久化,这样,即便系统重启后,再次启动程序也可以从磁盘文件读取之前存储的数据到内存进行初始化。

基于内存存取数据需要借助特定的数据结构,在 Go 语言中,这些数据结构包括基本类型(数字、字符串)、数组(array)、切片(slice)、字典(map)、结构体(struct)等,下面我们来简单演示如何基于 Go 语言的这些数据结构实现用户数据的临时存储。

在这个示例中,我们将创建用于存储文章数据的字典数据结构,并且在字典中存放多个通过结构体表示的文章数据(详细细节已经通过注释标注,这里不一一介绍了),最后从这些字典中读取数据并打印出来:

package main

import "fmt"

// 存放文章信息的 Post 结构体
type Post struct {
    Id int
    Title string
    Content string
    Author string
}

// 以 ID 字段为键的 Post 字典
var PostsById map[int]*Post
// 以作者字段为键的 Post 切片字典(一个作者可能对应多篇文章)
var PostsByAuthor map[string][]*Post

// 添加 Post 实例到对应的字典
func store(post Post) {
    PostsById[post.Id] = &post
    PostsByAuthor[post.Author] = append(PostsByAuthor[post.Author], &post)
}

func main()  {
    // 初始化字典
    PostsById = make(map[int]*Post)
    PostsByAuthor = make(map[string][]*Post)

    // 初始化文章信息
    post1 := Post{Id: 1, Title: "PHP 全栈工程师指南", Content: "基于 Laravel + Vue.js 开发 Web 项目", Author: "学院君"}
    post2 := Post{Id: 2, Title: "Go 入门教程", Content: "Go 语言基础语法和使用指南", Author: "学院君"}
    post3 := Post{Id: 3, Title: "Go Web 编程", Content: "基于 Gin 框架构建 Web 项目", Author: "学院君"}
    post4 := Post{Id: 4, Title: "微服务从入门到实践", Content: "基于 Laravel + go-micro 框架构建微服务", Author: "学院君"}

    // 存储文章到字典
    store(post1)
    store(post2)
    store(post3)
    store(post4)

    // 测试1:打印特定文章(从字典通过 ID 获取文章)
    fmt.Println(PostsById[1])
    fmt.Println(PostsById[2])

    // 测试2:打印特定文章(从字典通过作者获取文章切片)
    for _, post := range PostsByAuthor["学院君"] {
        fmt.Println(post)
    }
}

执行上述代码,打印结果如下:

-w740

其中前面两条是从 PostsById 字典中获取的数据,后面四条是从 PostsByAuthor 字典中获取的数据。

以上演示的是从内存数据结构中插入和查询数据,你还可以基于这些 Go 内置数据结构支持的语法实现数据修改和删除功能:

// 修改数据
PostsById[1].Author = "学院君小号"
// 删除数据
delete(PostsByAuthor, "学院君")

再次打印字典:

// 测试3:再次打印字典
fmt.Printf("%#v\n", PostsById[1])
for _, post := range PostsByAuthor["学院君"] {
    fmt.Println(post)
}

可以看到这次 PostsById[1] 对应的 Post.Author 字段值变成了 学院君小号,而 PostsByAuthor 字典为空(未打印出任何信息):

-w1040

这样一来,我们就结合 Go 内置的基本类型、切片、字典、结构体实现了简单的基于内存存储的数据增删改查功能,虽然效率是最高的,但是如前面所说,基于内存的数据存储无法实现持久化,另外,内存空间是有限的,几十几百条数据存储到内存还行,要是成千上万、乃至百万千万级数据存储到内存也是不现实的,要持久化存储大量数据,需要借助磁盘文件,下篇教程,学院君就来给大家介绍如何将用户数据存储到磁盘。


点赞 取消点赞 收藏 取消收藏

<< 上一篇: Go 视图模板篇(五):模板布局和继承

>> 下一篇: 文件存储(一):通过 JSON 格式序列化文本数据