Redis和MySQL结合的Web服务示例
脚本如下
package main
import (
"database/sql"
"encoding/json"
"fmt"
"github.com/go-redis/redis/v8"
"log"
"net/http"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
var db *sql.DB
var redisClient *redis.Client
type User struct {
ID int `json:"id"`
UserName string `json:"username"`
Email string `json:"email"`
}
func main() {
// 连接MySQL
var err error
db, err = sql.Open("mysql", "root:xxxx@tcp(xxxx:13306)/test001")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 连接Redis
redisClient = redis.NewClient(&redis.Options{
Addr: "xxxx:16379",
Password: "fdsfd23d",
DB: 0,
})
// 创建路由
r := mux.NewRouter()
r.HandleFunc("/user/{id}", getUserHandler).Methods("GET")
r.HandleFunc("/user", createUserHandler).Methods("POST")
// 启动Web服务
fmt.Println("Server is running on :8080")
log.Fatal(http.ListenAndServe(":8080", r))
}
func getUserHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
userID := vars["id"]
var user User
var userJSON []byte
var err error
// 尝试从Redis缓存获取用户信息
userJSONStr, err := redisClient.Get(r.Context(), "user:"+userID).Result()
if err == nil {
// 缓存命中,直接使用
userJSON = []byte(userJSONStr)
} else if err != redis.Nil {
log.Printf("Redis error: %v", err)
// 继续执行,尝试从数据库获取
}
// 如果Redis中没有数据,从MySQL查询
if userJSON == nil {
err = db.QueryRow("SELECT id, username, email FROM users WHERE id = ?", userID).Scan(&user.ID, &user.UserName, &user.Email)
if err != nil {
if err == sql.ErrNoRows {
http.Error(w, "User not found", http.StatusNotFound)
} else {
log.Printf("Database error: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
return
}
// 将用户信息转换为JSON
userJSON, err = json.Marshal(user)
if err != nil {
log.Printf("Failed to marshal user: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
// 将用户信息存入Redis缓存
err = redisClient.Set(r.Context(), "user:"+userID, userJSON, 5*time.Minute).Err()
if err != nil {
log.Printf("Failed to cache user: %v", err)
// 继续执行,不返回错误,因为我们仍然可以向客户端返回数据
}
}
// 返回用户信息
w.Header().Set("Content-Type", "application/json")
w.Write(userJSON)
}
func createUserHandler(w http.ResponseWriter, r *http.Request) {
var user User
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 将用户信息插入MySQL
result, err := db.Exec("INSERT INTO users (username, email) VALUES (?, ?)", user.UserName, user.Email)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
id, _ := result.LastInsertId()
user.ID = int(id)
// 将新用户信息缓存到Redis
userJSON, _ := json.Marshal(user)
err = redisClient.Set(r.Context(), fmt.Sprintf("user:%d", user.ID), userJSON, 5*time.Minute).Err()
if err != nil {
log.Printf("Failed to cache new user: %v", err)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# 测试
redis用户信息
1
上次更新: 2024/09/01, 20:26:32