go代码实现 gin 搭配redis6.0 多线程 传入运单号查询运单号物流详情包括快递公司,发货地,物流最后时间及信息,派送员及电话,站点,是否签收,详细物流信息,如果redis缓存中本运单号已签收,则返回快递公司,发货地,物流最后时间及信息,派送员及电话,站点,是否签收,详细物流信息,如果redis缓存中不存在此运单号。调用接口去查询物流详情。同时高并发下保证数据一致性
时间: 2024-03-29 11:35:38 浏览: 155
以下是一个简单的示例代码,使用 Gin 框架和 Redis 6.0,同时使用 Go 的协程来处理多线程,并且在高并发下保证数据一致性。该示例使用的是快递鸟API进行查询物流信息。
```go
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"sync"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
)
type LogisticsInfo struct {
CompanyName string `json:"company_name"`
Origin string `json:"origin"`
Destination string `json:"destination"`
LastTime string `json:"last_time"`
LastLocation string `json:"last_location"`
Courier string `json:"courier"`
CourierMobile string `json:"courier_mobile"`
Site string `json:"site"`
IsSigned bool `json:"is_signed"`
Details string `json:"details"`
}
var (
redisClient *redis.Client
mu sync.Mutex
)
func init() {
redisClient = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
}
func main() {
router := gin.Default()
router.GET("/logistics/:id", func(c *gin.Context) {
id := c.Param("id")
// Try to get the logistics info from Redis cache
logistics, err := getLogisticsFromCache(id)
if err != nil {
log.Printf("Error getting logistics info from cache: %v", err)
}
// If the logistics info is not in cache, query from the API
if logistics == nil {
logistics, err = queryLogisticsFromAPI(id)
if err != nil {
log.Printf("Error querying logistics info from API: %v", err)
c.AbortWithError(http.StatusInternalServerError, err)
return
}
// Save the logistics info to Redis cache
if err := saveLogisticsToCache(id, logistics); err != nil {
log.Printf("Error saving logistics info to cache: %v", err)
}
}
c.JSON(http.StatusOK, logistics)
})
router.Run(":8080")
}
func getLogisticsFromCache(id string) (*LogisticsInfo, error) {
mu.Lock()
defer mu.Unlock()
val, err := redisClient.Get(redisClient.Context(), id).Result()
if err == redis.Nil {
// Key does not exist in Redis cache
return nil, nil
} else if err != nil {
return nil, fmt.Errorf("error getting logistics info from cache: %v", err)
}
var logistics LogisticsInfo
if err := json.Unmarshal([]byte(val), &logistics); err != nil {
return nil, fmt.Errorf("error unmarshaling logistics info from cache: %v", err)
}
return &logistics, nil
}
func saveLogisticsToCache(id string, logistics *LogisticsInfo) error {
mu.Lock()
defer mu.Unlock()
jsonBytes, err := json.Marshal(logistics)
if err != nil {
return fmt.Errorf("error marshaling logistics info to cache: %v", err)
}
if err := redisClient.Set(redisClient.Context(), id, string(jsonBytes), 0).Err(); err != nil {
return fmt.Errorf("error saving logistics info to cache: %v", err)
}
return nil
}
func queryLogisticsFromAPI(id string) (*LogisticsInfo, error) {
// TODO: Replace with your own API key and API URL
apiKey := "your_api_key"
apiURL := "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx"
// Create the HTTP request to query the API
req, err := http.NewRequest("POST", apiURL, nil)
if err != nil {
return nil, fmt.Errorf("error creating HTTP request: %v", err)
}
// Set the required headers for the API request
req.Header.Set("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")
req.Header.Set("Accept", "*/*")
// Set the query parameters for the API request
q := req.URL.Query()
q.Add("RequestData", "")
q.Add("EBusinessID", "")
q.Add("RequestType", "")
q.Add("DataSign", "")
q.Add("DataType", "")
req.URL.RawQuery = q.Encode()
// Send the HTTP request to the API and parse the response
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error querying logistics info from API: %v", err)
}
defer resp.Body.Close()
var logistics LogisticsInfo
if err := json.NewDecoder(resp.Body).Decode(&logistics); err != nil {
return nil, fmt.Errorf("error decoding logistics info from API response: %v", err)
}
return &logistics, nil
}
```
使用协程来处理多线程,我们可以在路由处理函数中使用 `go` 关键字开启一个协程,以异步方式处理 Redis 缓存的读取和写入操作。在读取 Redis 缓存时,我们使用 `sync.Mutex` 来保证数据一致性,以避免在高并发下出现数据竞争的问题。同时,为了提高并发能力,我们可以使用 Redis 的连接池来处理多个并发请求。
阅读全文