目录
RPC 服务使用 GORM:在 GO-ZERO 框架中实现高效数据持久化
在 GO-ZERO 框架中,RPC 服务常常需要与数据库进行交互以实现数据的持久化。GORM 是一个强大的 Go 语言 ORM 库,将其与 RPC 服务结合使用可以提高开发效率。本文将详细介绍如何在 RPC 服务中使用 GORM,包括创建项目结构、编写 proto 文件、配置数据库连接、生成代码、编写服务逻辑以及进行数据操作等步骤,并附上完整的代码示例。
一、项目结构创建
- 新建项目目录
- 创建一个新的目录,例如
rpc_gorm_demo,作为项目的根目录。 - 在
rpc_gorm_demo目录下创建rpc目录,用于存放 RPC 相关的文件。
- 创建一个新的目录,例如
- 创建内部目录结构
- 在
rpc目录下创建user目录,用于存放用户相关的 RPC 服务文件(这里以用户服务为例,可根据实际需求创建多个不同的服务目录)。 - 在
user目录下创建etc、internal和model目录。etc目录用于存放服务的配置文件,internal目录用于存放服务的内部逻辑代码,model目录用于存放与数据库表对应的模型结构体和操作方法。
- 在
二、编写 proto 文件
- 创建 user.proto 文件
- 在
rpc/user目录下创建user.proto文件。 - 定义服务接口,例如创建一个名为
UserRpc的服务,包含一个GetUser方法,该方法接收一个UserRequest类型的参数(包含id字段),并返回一个UserResponse类型的结果(包含id、name等字段)。 - 示例代码如下:
- 在
syntax = "proto3";
service UserRpc {
rpc GetUser (UserRequest) returns (UserResponse);
}
message UserRequest {
int32 id = 1;
}
message UserResponse {
int32 id = 1;
string name = 2;
}
三、配置数据库连接
- 安装 GORM 依赖
- 在终端中执行
go get gorm.io/gorm命令安装 GORM 库,同时可能还需要安装相应的数据库驱动,例如对于 MySQL 数据库,执行go get gorm.io/driver/mysql。
- 在终端中执行
- 编写连接函数(initGorm)
- 在项目中创建一个用于初始化 GORM 连接的函数,例如在
main.go文件中(或者根据项目结构创建一个专门的数据库连接文件)。 - 示例代码如下:
- 在项目中创建一个用于初始化 GORM 连接的函数,例如在
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"rpc_gorm_demo/config" // 假设配置文件在config目录下,根据实际情况调整
)
func initGorm() *gorm.DB {
// 获取配置文件中的MySQL连接信息
mysqlStr := config.Config.Mysql.DataSource
// 连接数据库
db, err := gorm.Open(mysql.Open(mysqlStr), &gorm.Config{})
if err!= nil {
panic(err)
}
return db
}
- 在上述代码中,首先从配置文件中获取 MySQL 的连接字符串,然后使用
gorm.Open函数建立与 MySQL 数据库的连接。如果连接失败,程序将抛出panic异常,因为数据库连接是整个服务运行的基础,如果连接失败,服务启动也没有意义。
四、生成代码
- 执行生成命令
- 在终端中,进入
rpc目录(确保已安装goctl工具)。 - 执行以下命令将
user.proto文件转换为对应的 GO 代码:
- 在终端中,进入
goctl proto -I. --go_out=. --go-grpc_out=. user.proto
- 此命令会在
rpc目录下生成一系列文件,包括user.pb.go和user_grpc.pb.go等,这些文件包含了 RPC 服务的客户端和服务端的基本代码结构,以及与 proto 文件中定义的消息和服务对应的 Go 结构体和接口。
五、编写模型结构体和操作方法(Model 层)
- 创建 user 模型结构体(user/model/usermodel.go)
- 在
rpc/user/model目录下创建usermodel.go文件。 - 定义
User结构体,与数据库中的用户表字段对应。 - 示例代码如下:
- 在
package model
import "gorm.io/gorm"
type User struct {
ID int32 `gorm:"primaryKey"`
Name string `gorm:"size:50"`
}
- 编写 User 模型的操作方法(user/model/usermodel.go)
- 在
usermodel.go文件中,为User模型编写基本的操作方法,如FindUserByID用于根据用户 ID 查询用户信息。 - 示例代码如下:
- 在
func (u *User) FindUserByID(db *gorm.DB, id int32) (*User, error) {
var user User
result := db.Where("id =?", id).First(&user)
if result.Error!= nil {
return nil, result.Error
}
return &user, nil
}
六、编写服务逻辑
- 在 internal 目录下编写逻辑代码(user/internal/logic/userrpcgetuserlogic.go)
- 在
rpc/user/internal/logic目录下创建userrpcgetuserlogic.go文件(文件名根据生成的代码结构和实际需求而定)。 - 实现
GetUser方法的逻辑,在逻辑中调用User模型的操作方法从数据库获取用户信息并返回。 - 示例代码如下:
- 在
package logic
import (
"context"
"rpc_gorm_demo/rpc/internal/svc"
"rpc_gorm_demo/rpc/types/demo"
"rpc_gorm_demo/rpc/user/model"
)
type UserRpcGetUserLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUserRpcGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserRpcGetUserLogic {
return &UserRpcGetUserLogic{
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *UserRpcGetUserLogic) GetUser(in *demo.UserRequest) (*demo.UserResponse, error) {
// 获取数据库连接
db := l.svcCtx.DB
// 创建User模型实例
userModel := model.User{DB: db}
// 调用模型方法查询用户信息
user, err := userModel.FindUserByID(db, in.Id)
if err!= nil {
return nil, err
}
return &demo.UserResponse{Id: user.ID, Name: user.Name}, nil
}
七、配置服务
- 在 etc 目录下创建配置文件(user/etc/user.yaml)
- 在
rpc/user/etc目录下创建user.yaml文件。 - 配置服务的相关信息,如服务名称、监听地址和端口等,同时配置数据库连接信息(这里假设使用 MySQL 数据库)。
- 示例配置如下:
- 在
Name: userrpc
Host: 0.0.0.0
Port: 8080
Mysql:
DataSource: root:root@tcp(127.0.0.1:3306)/your_database?charset=utf8mb4&parseTime=True&loc=Local
- 将
your_database替换为实际的数据库名,根据实际情况修改用户名、密码和端口号等。
八、启动服务
- 创建 main 文件(user/main.go)
- 在
rpc/user目录下创建main.go文件(如果goctl生成代码时已包含则无需重复创建)。 - 编写启动服务的代码,例如:
- 在
package main
import (
"flag"
"fmt"
"github.com/zeromicro/go-zero/core/conf"
"github.com/zeromicro/go-zero/core/service"
"rpc_gorm_demo/rpc/internal/config"
"rpc_gorm_demo/rpc/internal/server"
"rpc_gorm_demo/rpc/internal/svc"
"rpc_gorm_demo/rpc/types/demo"
)
var configFile = flag.String("f", "etc/user.yaml", "the config file")
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
ctx := svc.NewServiceContext(c)
srv := server.NewUserRpcServer(ctx)
defer srv.Stop()
fmt.Printf("Starting rpc server at %s:%d...\n", c.Host, c.Port)
service.Group{}.Add(srv)
if err := service.Run(); err!= nil {
fmt.Printf("start rpc server error: %v\n", err)
}
}
- 启动服务
- 在终端中,进入
rpc/user目录。 - 执行
go run main.go(或者go run user.go,根据实际文件名而定)启动 RPC 服务。
- 在终端中,进入
通过以上步骤,我们成功地在 RPC 服务中使用了 GORM 进行数据库操作。在实际项目中,还可以进一步扩展和优化,如添加更多的数据库操作方法、实现事务处理、进行数据库连接池的配置等,以满足复杂的业务需求。同时,结合 GO-ZERO 框架的其他特性,如服务治理、熔断限流等,可以构建出更加稳定、高效的分布式系统。希望本文能够帮助大家更好地理解和应用 RPC 服务与 GORM 的结合。
2015

被折叠的 条评论
为什么被折叠?



