当前位置: 首页 > news >正文

go-zero(三) 数据库操作

go-zero 数据库操作

在本篇文章中,我们将实现一个用户注册和登录的服务。我们将为此构建一个简单而高效的 API,包括请求参数和响应参数的定义。

一、Mysql连接

1. 创建数据库和表

在 MySQL 中创建名为 test_zero的数据库,并创建`user 表

CREATE TABLE `users` (`id` BIGINT NOT NULL AUTO_INCREMENT,`username` VARCHAR(50) NOT NULL COLLATE 'utf8_general_ci',`password` VARCHAR(255) NOT NULL COLLATE 'utf8_general_ci',`created_at` TIMESTAMP NULL DEFAULT (CURRENT_TIMESTAMP),PRIMARY KEY (`id`) USING BTREE,UNIQUE INDEX `username` (`username`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

可以看到username 字段被我设置了唯一性即UNIQUE ,这里先解释一下,使用goctl 生成model代码的时候,它会自动帮我们生成增删改查等方法。

如果字段设置了唯一性,它会自动生成通过这个字段查找数据的方法,后续我希望通过username去查询和修改用户数据,所以这里设置了一下。

2. 创建API文件

接下来我们根据这个表,创建user.api文件,

syntax = "v1"type (// 定义注册接口的 json 请求体RegisterRequest {//请求体定义了 Username 和Password 字段, 并且都设置了不能为空Username string `json:"username" validate:"required"`   Password string `json:"password" validate:"required"`}// 定义注册接口的 json 响应体RegisterResponse {//响应体 定义类一个Message  用来返回结果Message string `json:"message"`}
)type (// 定义登录接口的 json 请求体LoginRequest {Username string `json:"username" validate:"required"`Password string `json:"password" validate:"required"`}// 定义登录接口的 json 响应体LoginResponse {//正常的业务逻辑,用户登录后会产生一个token,用来记录登录信息Token string `json:"token"`}
)@server (group:  user //  生成代码时都会被放到 user 目录下prefix: /v1 //定义路由前缀为 "/v1"
)// 定义 HTTP 服务
// 微服务名称为 user-api,生成的代码目录和配置文件将和 user 值相关
service user-api {// 定义用户注册接口//定义 http.HandleFunc 转换的 go 文件名称及方法@handler RegisterHandler// 请求方法为 post// 路由为 /register // 请求体为 RegisterRequest// 响应体为 RegisterResponse,响应体必须有 returns 关键字修饰post /register (RegisterRequest) returns (RegisterResponse)//用户登录@handler LoginHandlerpost /login (LoginRequest) returns (LoginResponse)
}

这个 API 的结构可以通过注释清晰地理解。在下面这段代码中,我们可以看到请求参数和响应参数之间通过 returns 进行修饰:

post /register (RegisterRequest) returns (RegisterResponse)

需要注意的是,请求参数响应参数并不总是必需的。

例如,在更新数据时,我们可以省略响应体,只保留请求参数:

post /update (UpdateUserInfoReq)

同样,当我们通过 token 获取数据时,也可以省略请求体,而只定义响应参数:

get /getinfo returns (UserInfoResp)

这样的灵活性使得 API 定义更加简洁明了。

3. 生成服务代码和model代码

我们创建一个新的项目,目录设置为user ,使用goctl通过user.api生成项目代码:

goctl api go --api user.api --dir ./

下面我们就演示怎么使用goclt 以及sql生成model , 在刚刚生成的项目中,在internal目录下创建一个modle的文件夹,然后再这个文件夹下面创建user.sql,把之前的sql语句粘贴进来,然后使用命令:

 goctl model mysql ddl --src user.sql --dir ./

当你看到 Done. 输出则代表生成成功了,帮我们生成了下面3个文件。

$ tree
.
├── usermodel.go
├── usermodel_gen.go
└── vars.go
  • usermodel.go: 定义数据库表的模型及其业务逻辑。
  • usermodel_gen.go: 自动生成的代码,包含数据库操作的实现。
  • vars.go: 全局变量和配置的定义,供各个模块使用。

4.查看model代码

现在我们来具体看下goctl帮我们生成的model代码,我们先看下usersmodel.go文件,

它帮我们定义了NewUsersModel 用来返回user表模型

// NewUsersModel returns a model for the database table.
//NewUsersModel 返回数据库表的模型
func NewUsersModel(conn sqlx.SqlConn) UsersModel {return &customUsersModel{defaultUsersModel: newUsersModel(conn),}
}

接着看下usersmodel_gen.go文件:

帮我们根据数据库自动生成了数据模型

 Users struct {Id        int64     `db:"id"`Username  string    `db:"username"`Password  string    `db:"password"`CreatedAt time.Time `db:"created_at"`}

给usersModel定义了基本的增删改查的接口

usersModel interface {Insert(ctx context.Context, data *Users) (sql.Result, error)FindOne(ctx context.Context, id int64) (*Users, error)FindOneByUsername(ctx context.Context, username string) (*Users, error)Update(ctx context.Context, data *Users) errorDelete(ctx context.Context, id int64) error
}

5.链接数据库

go-zero 提供了一个强大的 sqlx 工具,用于操作数据库。 所有 SQL 相关操作的包在 github.com/zeromicro/go-zero/core/stores/sqlx

在使用 go-zero 框架与数据库交互时,通常会遵循一系列的步骤和逻辑,下面是调用数据库的典型顺序和逻辑:

增加数据库连接配置

打开 etc\user-api.yaml文件,增加 MySQL 连接字符串:

#定义了一个名为MysqlDB的结构体,并有一个名为DbSource的字符串。
MysqlDB:# 字符串请根据实际配置环境更改DbSource: "root:root@tcp(127.0.0.1:3306)/test_zero"	

设置结构体,用来解析配置文件

现在我们需要把这个MysqlDB这个字段映射到 go-zero的结构体中,打开internal/config/config.go 文件,把代码修改为以下:

type Config struct {rest.RestConfMysqlDb struct{DbSource string `json:"DbSource"`}
}

我们之前提到过,Config 结构体中的字段与 YAML 文件中的字段可以不区分大小写,但必须保持一致,否则会导致解析错误。如果希望使用不同的名称,可以通过 json: 标签指定 YAML 文件中对应的字段名。

把数据库连接注册到服务上下文

go-zero提供了一个快捷的方式可以创建 Mysql 链接,接着我们就可以使用这个连接进行各种数据库操作:

func NewMysql(datasource string, opts ...SqlOption) SqlConn

我们先使用sqlx.NewMysql(c.MysqlDb.DbSource) 创建数据库连接,然后传给NewUsersModel,初始化UserModel,打开internal/svc/servicecontext.go文件,把代码修改为:

//ServiceContext 结构体用户封装服务的上下文信息,相当环境初始化type ServiceContext struct {Config config.Config  //UserModel: 类型为 model.UsersModel,表示与用户相关的数据库模型//用于处理与用户相关的数据操作(如用户的创建、读取、更新和删除等)UserModel model.UsersModel     
}
//NewServiceContext 是ServiceContext 的构造函数
//它接收配置参数并初始化 ServiceContext,确保服务可以访问所需的配置和数据模型
func NewServiceContext(c config.Config) *ServiceContext {return &ServiceContext{Config: c,  //把配置信息注册到服务上下文//通过调用 model.NewUsersModel 函数对UserModel 进行初始化//sqlx.NewMysql 是数据库连接,链接字符串为config中的MysqlDb.DbSourceUserModel:   model.NewUsersModel(sqlx.NewMysql(c.MysqlDb.DbSource)),}
}

sqlx.NewMysql 是 sqlx 包中的一个函数,通常用于创建一个新的 MySQL 数据库连接,我们可以看下它在go-zero中的代码, 就是传入datasource 字符串,然后返回SqlConn 数据库连接

func NewMysql(datasource string, opts ...SqlOption) SqlConn {opts = append([]SqlOption{withMysqlAcceptable()}, opts...)return NewSqlConn(mysqlDriverName, datasource, opts...)
}

二、CURD演示

1. 实现注册服务(查、赠)

现在我们开始实现注册逻辑
打开internal/logic/user/registerlogic.go文件,修改代码如下:

func (l *RegisterLogic) Register(req *types.RegisterRequest) (resp *types.RegisterResponse, err error) {// todo: add your logic here and delete this lineuserModel := l.svcCtx.UserModel  //从服务上下文获取UserModel //调用FindOneByUsername查询用户数据,判断用户是否已经注册//req.Username 从请求信息中获取 Usernameuser, _ := userModel.FindOneByUsername(l.ctx, req.Username)//如果username不为空说明已经注册if user != nil {//已经存在用户return nil, err}//插入新的数据_, err = userModel.Insert(l.ctx, &model.Users{Username:  req.Username,Password:  req.Password,CreatedAt: time.Now(),})if err != nil {//	注册失败return nil, err}//返回响应信息return &types.RegisterResponse{Message: "注册成功",}, nil
}

我们先运行程序,测试一下

在这里插入图片描述

2.实现登录服务 (查)

现在我们开始实现=登录逻辑
打开internal/logic/user/loginlogic.go文件,修改代码如下:

func (l *LoginLogic) Login(req *types.LoginRequest) (resp *types.LoginResponse, err error) {// todo: add your logic here and delete this line//因为我们目前还没涉及到jwt鉴权,所以先把token当面message使用userModel := l.svcCtx.UserModeluser, _ := userModel.FindOneByUsername(l.ctx, req.Username)//查询username判断是否有数据if user != nil { //如果有数据,密码是否和数据库匹配if req.Password == user.Password {return &types.LoginResponse{Token: "登录成功",}, nil} else {return &types.LoginResponse{Token: "密码错误",}, nil}} else {return &types.LoginResponse{Token: "用户未注册",}, nil}}

运行项目

http://www.lryc.cn/news/487924.html

相关文章:

  • SQL面试题——间隔连续问题
  • vim配置 --> 在创建的普通用户下
  • (计算机毕设)基于SpringBoot+Vue的房屋租赁系统的设计与实现
  • 【含开题报告+文档+PPT+源码】基于SpringBoot的医院药房管理系统
  • 基于SpringBoot的“数码论坛系统设计与实现”的设计与实现(源码+数据库+文档+PPT)
  • Linux-第2集-打包压缩 zip、tar WindowsLinux互传
  • 项目进度计划表:详细的甘特图的制作步骤
  • Cargo Rust 的包管理器
  • 【Rust 编程语言工具】rustup-init.exe 安装与使用指南
  • 集群聊天服务器(12)nginx负载均衡器
  • 数据挖掘英语及概念
  • springboot第82集:消息队列kafka,kafka-map
  • sql server查看当前正在执行的sql
  • STM32设计学生宿舍监测控制系统-分享
  • HAproxy 详解
  • 间接采购管理:主要挑战与实战策略
  • 2411rust,正与整128
  • 将 HTML 转换为 JSX:JSX 和 JSX 规则
  • 将 FastAPI 部署到生产服务器(一套 全)
  • 题解 洛谷 Luogu P1873 [COCI 2011/2012 #5] EKO / 砍树 二分答案 C/C++
  • SpringCloud SaToken整合微服务 集成Redis 网关路由权限拦截 服务间内部调用鉴权
  • Oracle ADB 导入 BANK_GRAPH 的学习数据
  • 优化 MFC CGridCtrl 的表格布局与功能
  • koa-body 的详细使用文档
  • 信息系统与互联网中的安全、隐私及伦理问题
  • Java安全—log4j日志FastJson序列化JNDI注入
  • 【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【DSP指令加速篇】
  • Python中如何判断一串文本是不是数字
  • 基于YOLOv8深度学习的智慧农业山羊行为检测系统研究与实现(PyQt5界面+数据集+训练代码)
  • Redis环境部署(主从模式、哨兵模式、集群模式)