Go语言编程笔记16:存储数据
几乎任何程序都绕不开读写数据,只不过具体的数据存储介质和方式有所不同。本篇文章将从多种数据存储方式进行探讨各种存储方式如何实现以及优劣。
内存
最简单也是最容易想到的方式大概就是用内存存储数据,事实上这也是大多数初学者不经意间最先学到的。
乍一听用内存存储数据显得很高级,其实所有程序运行时申请的变量都是在使用内存来存储数据。
不过作为Web应用,使用内存存储数据必须考虑并发,所以应当使用通道或者互斥锁来实现并发的数据读写。这里给出一个简陋的论坛应用。这个非常简陋的应用只实现了几个核心功能:
/login
展现一个登陆页面,输入任意的非空用户名和密码可以登录。/all_articles
展示目前所有的帖子,包含帖子序号、内容、用户名。并且可以在最下方的文本框输入信息并添加一个新的帖子。可以通过上方的exit
链接注销用户并退出。
下面给出完整程序:
main.go
package main
import (
"errors"
"fmt"
"html/template"
"log"
"net/http"
"sync"
"time"
)
type Article struct {
Id int
Content string
Author string
}
var aMutex sync.RWMutex
var articles []*Article
const COOKIE_USER_NAME = "user_name"
func addArticle(content string, author string) {
aMutex.Lock()
defer aMutex.Unlock()
aLen := len(articles)
newArticle := Article{
Id: aLen,
Content: content,
Author: author,
}
articles = append(articles, &newArticle)
}
func getArticles() []Article {
aMutex.RLock()
defer aMutex.RUnlock()
var aCopy []Article
for _, a := range articles {
aCopy = append(aCopy, *a)
}
return aCopy
}
func getUserName(rw http.ResponseWriter, r *http.Request) (userName string, err error) {
lc, err := r.Cookie(COOKIE_USER_NAME)
if err != nil || lc.Value == "" {
//去登录
rw.Header().Set("Location", "/login")
rw.WriteHeader(301)
err = errors.New("need login")
return
}
userName = lc.Value
return
}
func doLogin(rw http.ResponseWriter, user string) {
lc := http.Cookie{
Name: COOKIE_USER_NAME,
Value: user,
}
rw.Header().Set("Set-Cookie", lc.String())
}
func unLogin(rw http.ResponseWriter) {
lc := http.Cookie{
Name: COOKIE_USER_NAME,
Value: "",
Expires: time.Unix(1, 0),
MaxAge: -1,
}
rw.Header().Set("Set-Cookie", lc.String())
}
func login(rw http.ResponseWriter, r *http.Request) {
t := template.Must(template.ParseFiles("login.html"))
t.Execute(rw, nil)
}
func loginCheck(rw http.ResponseWriter, r *http.Request) {
un := r.PostFormValue("user_name")
p := r.PostFormValue("password")
if un == "" && p == "" {
log.Fatal(errors.New("user name and password is empty"))
}
doLogin(rw, un)
rw.Header().Set("Location", "/all_articles")
rw.WriteHeader(301)
}
func allArticles(rw http.ResponseWriter, r *http.Request) {
data := struct {
UserName string
Articles []Article
}{
}
data.Articles = getArticles()
un, err := getUserName(rw, r)
if err != nil {
fmt.Println(err)
rw.Header().Set("Location", "/login")
rw.WriteHeader(301)
return
}
data.UserName = un
t := template.Must(template.ParseFiles("articles.html"))
t.Execute(rw, data)
}
func addArticleHandle(rw http.ResponseWriter, r *http.Request) {
content := r.PostFormValue("content")
author, err := getUserName(rw, r)
if err != nil {
fmt.Println(err)
return
}
addArticle(content, author)
rw.Header().Set