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 LoginHandler
	post /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) error
    Delete(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.RestConf
	
	MysqlDb 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.DbSource
		UserModel:   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 line

	userModel := l.svcCtx.UserModel  //从服务上下文获取UserModel 

	//调用FindOneByUsername查询用户数据,判断用户是否已经注册
	//req.Username 从请求信息中获取 Username
	user, _ := 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.UserModel
	user, _ := 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
	}
	
}

运行项目

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/920748.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

23种设计模式-模板方法(Template Method)设计模式

文章目录 一.什么是模板方法模式?二.模板方法模式的特点三.模板方法模式的结构四.模板方法模式的应用场景五.模板方法模式的优缺点六.模板方法模式的C实现七.模板方法模式的JAVA实现八.代码解析九.总结 类图: 模板方法设计模式类图 一.什么是模板方法模…

uniapp实现开发遇到过的问题(持续更新中....)

1. 在ios模拟器上会出现底部留白的情况 解决方案: 在manifest.json文件,找到开源码视图配置,添加如下: "app-plus" : {"safearea":{"bottom":{"offset" : "none" // 底部安…

Python Matplotlib 安装指南:使用 Miniconda 实现跨 Linux、macOS 和 Windows 平台安装

Python Matplotlib 安装指南:使用 Miniconda 实现跨 Linux、macOS 和 Windows 平台安装 Matplotlib是Python最常用的数据可视化工具之一,结合Miniconda可以轻松管理安装和依赖项。在这篇文章中,我们将详细介绍如何使用Miniconda在Linux、mac…

【element-tiptap】Tiptap编辑器核心概念----结构篇

core-concepts 前言:这篇文章来介绍一下 Tiptap 编辑器的一些核心概念 (一)结构 1、 Schemas 定义文档组成方式。一个文档就是标题、段落以及其他的节点组成的一棵树。 每一个 ProseMirror 的文档都有一个与之相关联的 schema,…

window的wsl(Ubuntu)安装kafka步骤

环境:Win11 WSL(Linux子系统Ubuntu) apache-zookeeper-3.9.3-bin kafka_2.12-3.8.1 思路:apache上分别下载zookeeper和kafka,在wsl环境安装。在kafka上创建消息的topic,发送消息,接受消息,验证是否安…

Notepad++--在开头快速添加行号

原文网址:Notepad--在开头快速添加行号_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Notepad怎样在开头快速添加行号。 需求 原文件 想要的效果 方法 1.添加点号 Alt鼠标左键,从首行选中首列下拉,选中需要添加序号的所有行的首列&#xff…

机器学习基础06_梯度下降

目录 一、为什么使用梯度下降 二、什么是梯度下降 三、为什么要用梯度下降 四、怎么进行梯度下降 1、微分 1.单变量的微分 2.多变量的微分 2、梯度 3、步骤 (1)学习率α (2)梯度(导数)前的负号 4、实例实现 五、sklearn梯度下降 一、为什么使用梯度下降 前面利用正…

《Vue零基础入门教程》第二课:搭建开发环境

往期内容: 《Vue零基础入门教程》第一课:Vue简介 1 搭建开发环境 Vue环境分为两种 不使用构建工具使用构建丁具 首先,我们会介绍 不使用构建工具 的环境,在组件化章节中介绍 使用构建工具 的方式 1) 初始化 使用如下指令初始化 npm i…

【IDEA】解决总是自动导入全部类(.*)问题

文章目录 问题描述解决方法 我是一名立志把细节说清楚的博主,欢迎【关注】🎉 ~ 原创不易, 如果有帮助 ,记得【点赞】【收藏】 哦~ ❥(^_-)~ 如有错误、疑惑,欢迎【评论】指正探讨,我会尽可能第一时间回复…

Acme PHP - Let‘s Encrypt

Lets Encrypt是一个于2015年三季度推出的数字证书认证机构,旨在以自动化流程消除手动创建和安装证书的复杂流程,并推广使万维网服务器的加密连接无所不在,为安全网站提供免费的SSL/TLS证书。 使用PHP来更新证书: Acme PHP | Rob…

【Linux清空显存占用】Linux 系统中清理 GPU 显存

操作指令 # 查看NVIDIA GPU状态和进程 nvidia-smi # 查找所有包含"python"的进程 ps -ef grep python # 强制结束进程号为3023的进程 kill -9 3023截图演示 在 Linux 系统中清理 GPU 显存可以采用以下方法: 1. 终止特定进程(常用方法&#x…

【网络】网络抓包与协议分析

网络抓包与协议分析 一. 以太网帧格式分析 这是以太网数据帧的基本格式,包含目的地址(6 Byte)、源地址(6 Byte)、类型(2 Byte)、数据(46~1500 Byte)、FCS(4 Byte)。 Mac 地址类型 分为单播地址、组播地址、广播地址。 单播地址:是指第一个字节的最低位…

IC脚本之perl

Perl 是一种功能丰富的计算机程序语言,运行在超过100种计算机平台上。IC flow 的 流传的古老版本大多是也是使用这种语言,这里会对Perl的常用知识点进行总结。 Note: 所有的语句必须以 “ ;”结尾;所有的数据必须先定义才可以使…

MEMS硅麦克风应用电子烟雾化产业稳步爬升,耐高温、 防油、防酸、防腐蚀等性能优势和可实现自动化贴片及极高的一致性等特性使其必将成为主流

全球范围内,电子烟行业正处于快速发展的阶段。随着消费者健康意识的提升和对传统烟草制品替代品需求的增加,电子烟市场获得了显著的增长。然而,伴随而来的监管挑战和消费者期待的变化,也促使行业不断进行技术创新和产品优化。特别…

双因子认证:统一运维平台安全管理策略

01双因子认证概述 双因子认证(Two-Factor Authentication,简称2FA)是一种身份验证机制,它要求用户提供两种不同类型的证据来证明自己的身份。这通常包括用户所知道的(如密码)、用户所拥有的(如…

快慢指针应用---环型链表的应用

1.题目--判断链表是否成环 已经了解了快慢指针的应用原理,引申:用快慢指针去判断链表是否成环。 题解 简而言之,在fast和slow指针遍历的这种情况下,如果链表是成环的,那么在循环遍历了两次后,fast指针就会…

三、计算机视觉_06YOLO基础知识

1、YOLO概述 1.1 定义 YOLO(You Only Look Once)是一种流行的对象检测和图像分割模型,由华盛顿大学的 Joseph Redmon 和 Ali Farhadi 于 2015 年推出,因其高速和准确性而迅速受到欢迎 在目标检测领域,传统方法&…

Python Matplotlib 数据可视化全面解析:选择它的七大理由与入门简介

Python Matplotlib数据可视化全面解析:选择它的七大理由与入门简介 本文介绍了Matplotlib这一强大而灵活的数据可视化工具,涵盖其基本概念、独特优势以及为何在众多Python绘图库中脱颖而出。Matplotlib具有广泛的社区支持、高度自定义能力、多样的绘图类…

【Spring Boot】用 MyBatis 实现数据的 CRUD

用 MyBatis 实现数据的 CRUD 1.创建项目 & 引入依赖2.实现数据表的自动初始化3.实现实体对象建模4.实现实体和数据表的映射关系5.实现增加、删除、修改和查询功能6.配置分页功能6.1 增加分页支持6.2 创建分页配置类 7.实现分页控制器8.创建分页视图 本篇博客将通过 MyBatis…

数据结构-二叉树_堆

目录 1.二叉树的概念 ​编辑1.1树的概念与结构 1.2树的相关语 1.3 树的表示 2. ⼆叉树 2.1 概念与结构 2.2 特殊的⼆叉树 2.2.2 完全⼆叉树 2.3 ⼆叉树存储结构 2.3.1 顺序结构 2.3.2 链式结构 3. 实现顺序结构⼆叉树 3.2 堆的实现 3.2.2 向下调整算法 1.二叉树的概…