B站微服务框架Kratos详细教程(7)- 数据库
开始使用
由于kratos
使用了wire
依赖注入框架,开始使用前,建议先了解相关教程:依赖注入wire使用详解
配置
打开配置文件configs/mysql.toml
,修改为自己的服务器配置:
[Client]
addr = "127.0.0.1:3306"
dsn = "{user}:{password}@tcp(127.0.0.1:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8"
readDSN = ["{user}:{password}@tcp(127.0.0.2:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "200ms"
execTimeout = "300ms"
tranTimeout = "400ms"
在该配置文件中我们可以配置mysql的读和写的dsn、连接地址addr、连接池的闲置连接数idle、最大连接数active以及各类超时。
如果配置了readDSN,在进行读操作的时候会优先使用readDSN的连接,readDSN可以只配一个地址。
初始化
打开文件internal/dao/dao.go
在该文件中的New
方法接收外部数据库连接池对象db *sql.DB
, 也可以像官方文档说的, 直接在dao
中初始化
这里涉及到依赖注入, 具体可以查看di/wire_gen.go
文件
依赖注入相关可查看这篇文章: 依赖注入wire使用详解
在model/model.go
文件中添加结构体
type User struct {
Uid int32
Nickname string
Age int32
Uptime int32
Addtime int32
}
在dao/dao.go
中新增接口
type Dao interface {
Close()
Ping(ctx context.Context) (err error)
// bts: -nullcache=&model.Article{ID:-1} -check_null_code=$!=nil&&$.ID==-1
Article(c context.Context, id int64) (*model.Article, error)
//新增接口
GetUser(c context.Context, uid int64) (user *model.User, err error)
}
新增文件dao/dao.user.go
, 实现接口
package dao
import (
"context"
"dbserver/internal/model"
"fmt"
"github.com/go-kratos/kratos/pkg/database/sql"
"github.com/go-kratos/kratos/pkg/log"
"time"
)
//查询用户
func (d *dao)GetUser(c context.Context, uid int64) (user *model.User, err error){
querySql := fmt.Sprintf("SELECT * FROM `users` WHERE uid=?;")
user = new(model.User)
err = d.db.QueryRow(c, querySql, uid).Scan(&user.Uid, &user.Nickname, &user.Age, &user.Uptime, &user.Addtime)
if err != nil && err != sql.ErrNoRows {
log.Error("d.QueryRow error(%v)", err)
return
}
return user, nil
}
打开api/api.proto
, 增加测试http接口:
syntax = "proto3";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
// package 命名使用 {appid}.{version} 的方式, version 形如 v1, v2 ..
package demo.service.v1;
// NOTE: 最后请删除这些无用的注释 (゜-゜)つロ
option go_package = "api";
option (gogoproto.goproto_getters_all) = false;
service Demo {
rpc Ping(.google.protobuf.Empty) returns (.google.protobuf.Empty);
rpc SayHello(HelloReq) returns (.google.protobuf.Empty);
rpc SayHelloURL(HelloReq) returns (HelloResp) {
option (google.api.http) = {
get: "/say_hello"
};
};
rpc GetUser(GetReq) returns (Response) {
option (google.api.http) = {
get: "/getuser"
};
};
}
message HelloReq {
string name = 1 [(gogoproto.moretags) = 'form:"name" validate:"required"'];
}
message HelloResp {
string Content = 1 [(gogoproto.jsontag) = 'content'];
}
message GetReq {
int64 uid = 1 [(gogoproto.moretags) = 'form:"uid" validate:"required"'];
}
message Response {
string Content = 1 [(gogoproto.jsontag) = 'content'];
}
打开internal/service/service.go
, 增加接口实现:
//获取用户信息
func (s *Service) GetUser(ctx context.Context, req *pb.GetReq) (reply *pb.Response, err error) {
fmt.Printf("GetUser: %d", req.Uid)
user, err := s.dao.GetUser(ctx, req.Uid)
if err != nil {
fmt.Printf("GetUser %s Error", req.Uid)
return
}
res, _ := json.Marshal(user)
reply = &pb.Response{
Content: string(res),
}
return
}
进入api
目录, 重新生成pb文件
kratos tool protoc
这里需要注意的是,执行完这句话,就会在api.bm.go中实现proto文件里option (google.api.http)中定义的路由,实现在RegisterDemoBMServer方法中,并且在server下的http文件内的New调用。这种方法是直接用他的服务进行api的注册,还可以自己手动在http下的server中initRouter下定义自己的路由。
运行项目:
kratos run
打开浏览器:
获取单个用户信息:
http://localhost:8000/getuser?uid=3
返回信息:
{
"code": 0,
"message": "0",
"ttl": 1,
"data": {
"content": "{\"Uid\":3,\"Nickname\":\"soul\",\"Age\":22,\"Uptime\":1608102563,\"Addtime\":1608102563}"
}
}
到此, 已实现基本的数据库操作
事务
kratos/pkg/database/sql
包支持事务操作,具体操作示例如下:
开启一个事务:
tx := d.db.Begin()
if err = tx.Error; err != nil {
log.Error("db begin transcation failed, err=%+v", err)
return
}
在事务中执行语句:
res, err := tx.Exec(_demoSQL, did)
if err != nil {
return
}
rows := res.RowsAffected()
提交事务:
if err = tx.Commit().Error; err!=nil{
log.Error("db commit transcation failed, err=%+v", err)
}
回滚事务:
if err = tx.Rollback().Error; err!=nil{
log.Error("db rollback failed, err=%+v", rollbackErr)
}
grpc方式调用
上述那个方法使用proto注册服务的形式写的,所以也能使用grpc的方式调用。
http对应的grpc的服务文件他这里给你注册了。
所以说,你只需要,把api下的proto文件给别人,就可以了
这里我写上自己的测试代码
文件结构:这里直接把pb.go拿过来用了
image.png
package main
import (
"context"
"log"
"test/api"
"google.golang.org/grpc"
)
func main() {
conn, err := grpc.Dial("localhost:9000", grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
c := api.NewDemoClient(conn) //新建client
getUser(c)
}
//普通数据传输
func getUser(c api.DemoClient) {
character, err := c.GetUser(context.Background(), &api.HelloReq{
Name: "shitingbao",
})
if err != nil {
log.Println("err:", err)
}
log.Println("character:", character)
}
网友评论