存储
1. Mysql
之前的入门案例中,我们没有去连接数据库,接下来我们将数据库连上,并进行操作。
准备数据库:
docker-compose.yml
version: '3'
services:
mysql:
container_name: mysql8
image: mysql:${MYSQL_VERSION}
restart: always
ports:
- ${MYSQL_PORT}:3306
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: zero_mall
volumes:
- ${MYSQL_DIR}/data:/var/lib/mysql
- ${MYSQL_DIR}/conf:/etc/mysql/conf.d/
- ${MYSQL_DIR}/logs:/logs
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
Etcd:
container_name: etcd3
image: bitnami/etcd:${ETCD_VERSION}
deploy:
replicas: 1
restart_policy:
condition: on-failure
environment:
- ALLOW_NONE_AUTHENTICATION=yes
privileged: true
volumes:
- ${ETCD_DIR}/data:/bitnami/etcd/data
ports:
- ${ETCD_PORT}:2379
- 2380:2380
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
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
.env:
COMPOSE_PROJECT_NAME=gozero-demo-mall
ETCD_DIR=D:/go/project/gozero/etcd
ETCD_VERSION=3.5.6
ETCD_PORT=2379
MYSQL_VERSION=8.0.20
MYSQL_DIR=D:/go/project/gozero/mysql
MYSQL_PORT=3309
1
2
3
4
5
6
7
2
3
4
5
6
7
创建表:
CREATE TABLE `user` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`gender` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
1
2
3
4
5
6
2
3
4
5
6
1.1 添加配置
type Config struct {
zrpc.RpcServerConf
Mysql MysqlConfig
}
type MysqlConfig struct {
DataSource string
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Name: user.rpc
ListenOn: 127.0.0.1:8080
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc
Mysql:
DataSource: root:root@tcp(127.0.0.1:3309)/zero_mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
1.2 实现
创建连接:
package database
import "github.com/zeromicro/go-zero/core/stores/sqlx"
type DBConn struct {
Conn sqlx.SqlConn
}
func Connect(dataSource string) *DBConn {
sqlConn := sqlx.NewMysql(dataSource)
return &DBConn{
Conn: sqlConn,
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
实现sql:
package dao
import (
"context"
"fmt"
"user/database"
"user/internal/model"
)
type UserDao struct {
*database.DBConn
}
func NewUserDao(conn *database.DBConn) *UserDao {
return &UserDao{conn}
}
func (d *UserDao) Save(ctx context.Context, data *model.User) error {
sql := fmt.Sprintf("insert into %s (name,gender) values (?,?)", data.TableName())
result, err := d.Conn.ExecCtx(ctx, sql, data.Name, data.Gender)
if err != nil {
return err
}
id, err := result.LastInsertId()
if err != nil {
return err
}
data.Id = id
return nil
}
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
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
调用
func (l *GetUserLogic) SaveUser(in *user.UserRequest) (*user.UserResponse, error) {
// todo: add your logic here and delete this line
data := &model.User{
Name: in.GetName(),
Gender: in.GetGender(),
}
err := l.svcCtx.UserRepo.Save(context.Background(), data)
if err != nil {
return nil, err
}
return &user.UserResponse{
Id: strconv.FormatInt(data.Id, 10),
Name: data.Name,
Gender: data.Gender,
}, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
测试即可
2. Redis
go-zero框架使用的是go-redis
在这里,我们演示go-zero给我们提供的数据库缓存机制。
2.1 添加配置
type Config struct {
zrpc.RpcServerConf
Mysql MysqlConfig
CacheRedis cache.CacheConf
}
1
2
3
4
5
2
3
4
5
CacheRedis:
- Host: 127.0.0.1:6379
Type: node
1
2
3
2
3
docker-compose.yml:
Redis:
container_name: redis6
image: redis:${REDIS_VERSION}
restart: always
volumes:
- ${REDIS_DIR}/data:/data
- ${REDIS_DIR}/conf/redis.conf:/etc/redis/redis.conf
ports:
- ${REDIS_PORT}:6379
command: redis-server /etc/redis/redis.conf
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
.env:
REDIS_VERSION=6.2.7
REDIS_PORT=6379
REDIS_DIR=D:/go/project/gozero/redis
1
2
3
2
3
redis.conf:
# 任意ip可访问
bind 0.0.0.0
# 自定义启动端口
port 6379
# rdb或aof文件存储位置
dir /data
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfilename "appendonly.aof"
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2.2 实现
package database
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type DBConn struct {
Conn sqlx.SqlConn
ConnCache sqlc.CachedConn
}
func Connect(dataSource string, conf cache.CacheConf) *DBConn {
sqlConn := sqlx.NewMysql(dataSource)
d := &DBConn{
Conn: sqlConn,
}
if conf != nil {
cachedConn := sqlc.NewConn(sqlConn, conf)
d.ConnCache = cachedConn
}
return d
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func (d *UserDao) FindById(ctx context.Context, id int64) (user *model.User, err error) {
user = &model.User{}
query := fmt.Sprintf("select * from %s where id = ?", user.TableName())
userIdKey := fmt.Sprintf("%s:%d", cacheUserIdPrefix, id)
err = d.ConnCache.QueryRowCtx(ctx, user, userIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
return conn.QueryRowCtx(ctx, v, query, id)
})
return
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {
// todo: add your logic here and delete this line
id, _ := strconv.ParseInt(in.Id, 10, 64)
userData, err := l.svcCtx.UserRepo.FindById(context.Background(), id)
if err != nil {
return nil, err
}
return &user.UserResponse{
Id: in.GetId(),
Name: userData.Name,
Gender: userData.Gender,
}, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
api:
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
var req types.IdRequest
if err := httpx.ParsePath(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := logic.NewUserLogic(r.Context(), h.svcCtx)
resp, err := l.GetUser(&req)
if err != nil {
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
{
Method: http.MethodGet,
Path: "/user/get/:id",
Handler: handler.GetUser,
},
1
2
3
4
5
2
3
4
5
func (l *UserLogic) GetUser(req *types.IdRequest) (*types.Response, error) {
userResponse, err := l.svcCtx.UserRpc.GetUser(context.Background(), &user.IdRequest{
Id: req.Id,
})
if err != nil {
return nil, err
}
return &types.Response{
Message: "success",
Data: userResponse,
}, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14