How should go implement L2 caching

Time:2021-10-19

1、 Demand

  • Implement L2 cache
  • After the program runs, it will prompt: “please enter the command:”. If you enter getall, the information of all personnel will be queried and displayed
  • Query MySQL for the first time, cache the results in redis, and set the expiration time of 60 seconds
  • For each subsequent query, if there is data in redis, it will be loaded from redis. If there is no data, repeat the operation in the previous step

2、 Connect mysql and execute query statements

First, implement requirement 2. When you enter the command getall, query and display the information of all personnel.

?
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
package main
import (
    "fmt"
    _"github.com/go-sql-driver/mysql"
    "github.com/jmoiron/sqlx"
)
type Human struct {
    Name string `db:"name"`
    Age int `db:"age"`
}
func main() {
    var cmd string
    for{
        Fmt.println ("please enter the command:")
        fmt.Scan(&cmd)
        switch cmd{
        case "getall":
            //Show everyone's information
            GetAllPeople()
        case "exit":
            //Exit program
            goto GAMEOVER
        default:
            FMT. Println ("the command entered is incorrect, please re-enter!")
        }
    }
    GAMEOVER:
    fmt.Println("GAME OVER")
}
func GetAllPeople()  {
    fmt.Println("allPeople")
    //Try to get the cache first
    GetPeopleFromRedis()
    db, _ := sqlx.Connect("mysql", "root:[email protected](localhost:3306)/mydb")
    defer db.Close()
    var people []Human
    err := db.Select(&people, "select name,age from person")
    if err!=nil{
        FMT. Println ("query failed! Err =" ", err")
    }
    fmt.Println(people)
    
    CachePeople2Redis(people)
}

The first step is to import the package. You need to underline the MySQL driver package, Because it is just a driver file, and it doesn’t need to call its API interface in code.
In the following structure, the following DB: “name” DB: “age” must be enclosed in inverse single quotation marks, otherwise an error will be reported at run time. (silly editor, there was a problem here at the beginning ~)

?
1
2
3
4
type Human struct {
    Name string `db:"name"`
    Age int `db:"age"`
}

Then the main function contains some basic grammar knowledge, using switch and goto.
The next step is to connect to the database. The database extension package sqlx is used here. In fact, the biggest advantage of sqlx package is in query, that is, it is optimized better when using select. It is more convenient than the original query.

?
1
db, _ := sqlx.Connect("mysql", "root:[email protected](localhost:3306)/mydb")

DriverName: MySQL, which means that the name of the drive is mysql, that is, the drive imported from “GitHub. COM / go SQL driver / MySQL” above.
Datasourcename is root: [email protected] (localhost: 3306) / mydb means account name: password @ TCP (IP: port) / database name.
This function cachepeople2redis (people) is used to cache query results to redis.

3、 Write an error handling function

?
1
2
3
4
5
6
func HandleError(err error,why string)  {
    if err != nil{
        fmt.Println(err,why)
        os.Exit(1)
    }
}

Because many errors need to be handled later, and error handling is also a feature of go, let’s write an error handling function first.

4、 Set L2 cache

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func CachePeople2Redis(people []Human)  {
    conn, _ := redis.Dial("tcp", "localhost:6379")
    defer conn.Close()
    for _,human := range people{
        humanStr := fmt.Sprint(human)
        _, err := conn.Do("rpush", "people", humanStr)
        if err != nil{
            FMT. Println ("cache failed (rpush people), err =", err ")
            return
        }
    }
    _, err := conn.Do("expire", "people", 66)
    if err!=nil{
        HandleError(err,"@expire people 60")
    }
    FMT. Println ("cache succeeded!")
}

Redis. Dial() is used to connect to redis. The network protocol, IP address and port number need to be given. The default port number of redis is 6379
Defer Conn. close() means that the connection with redis is ended after a delay. In order to save IO resources of the system, the connection needs to be closed in time! It’s easy for us to forget this at the beginning. We need to form a habit!
Conn. Do () is used to execute the database command. The first parameter is the command name, and the following parameter is the parameter of the database command. In the returned results, reply is the byte array [] byte type, and data type conversion needs to be carried out according to the specific business type.
This code first puts each human in the people array into the people list of redis. Then execute the expire command to set the expiration time of the list.
Execution succeeded! Here are the results:

Please enter the command:
getall
allPeople
[{Dayang 21} {Xiaofei 21} {Dahongpao 1} {Xiaofang 18}]
Cache succeeded!
Please enter the command:

Then go and see if it’s stored in the database.

?
1
2
3
4
5
127.0.0.1:6379> lrange people 0 -1
1) "{\xe5\xa4\xa7\xe6\x89\xac 21}"
2) "{\xe5\xb0\x8f\xe9\xa3\x9e 21}"
3) "{\xe5\xa4\xa7\xe7\xba\xa2\xe8\xa2\x8d 1}"
4) "{\xe5\xb0\x8f\xe8\x8a\xb3 18}"

After one minute, view the data in the redis database.

?
1
2
127.0.0.1:6379> lrange people 0 -1
(empty list or set)

It’s gone.

Write another function:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func GetPeopleFromRedis() (peopleStrs []string) {
    //Connect database
    conn, _ := redis.Dial("tcp", "localhost:6379")
    //Delayed shutdown
    defer conn.Close()
    //Execute command
    reply, err := conn.Do("lrange", "people", 0, -1)
    //Processing error
    HandleError(err,"@lrange people 0 -1")
    //Type conversion
    peopleStrs, err = redis.Strings(reply, err)
    //Print results
    FMT. Println ("cache fetch result:", peoplestrs, ERR)
    return
}

If there is in redis, you don’t need to get data from mysql. Use the lrange command directly from redis to obtain all the values of people.

This is the end of this article on how to implement the secondary cache of go. For more information about the secondary cache of go, please search the previous articles of developeppaper or continue to browse the relevant articles below. I hope you will support developeppaper in the future!