go-zero(三) 数据库操作

news2024/11/18 7:45:03

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
	}
	
}

运行项目

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

113页PPT制造业研发工艺协同及制造一体化

研发工艺协同及制造一体化解决方案是制造业数字化转型的重要组成部分,它涵盖了从产品设计到生产的全过程,旨在提高生产效率、降低成本、提升产品质量,并增强企业的市场竞争力。以下是对该解决方案的详细阐述: 一、方案概述 研发…

【MySQL 保姆级教学】事务的隔离级别(详细)--下(14)

事务的隔离级别 1. 如何理解事务的隔离性2. 事务隔离级别的分类3. 查看和设置事务隔离级别3.1 全局和会话隔离级别3.2 查看和设置隔离级别 4. 事务隔离级别的演示4.1 读未提交(Read Uncommitted)4.2 读已提交(Read Committed)4.3 …

手机ip地址异常怎么解决

在现代社会中,手机已成为我们日常生活中不可或缺的一部分,无论是工作、学习还是娱乐,都离不开网络的支持。然而,有时我们会遇到手机IP地址异常的问题,这不仅会影响我们的网络体验,还可能带来安全隐患。本文…

STM32低功耗设计NFC与无线距离感应智能钥匙扣

目录 目录 前言 一、本设计主要实现哪些很“开门”功能? 二、电路设计原理图 1.电路图采用Altium Designer进行设计: 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 在当今快速发展的物联网(IoT)时代&#xf…

Pyhon基础数据结构(列表)【蓝桥杯】

a [1,2,3,4,5] a.reverse() print("a ",a) a.reverse() print("a ",a)# 列表 列表(list)有由一系列按照特定顺序排序的元素组成 列表是有顺序的,访问任何元素需要通过“下标访问” 所谓“下标”就是指元素在列表从左…

关于win11电脑连接wifi的同时,开启热点供其它设备连接

背景: 我想要捕获手机流量,需要让手机连接上电脑的热点。那么问题来了,我是笔记本电脑,只能连接wifi上网,此时我的笔记本电脑还能开启热点供手机连接吗?可以。 上述内容,涉及到3台设备&#x…

SAP SD学习笔记13 - 出库确认(发货)之后的取消 - VL09

上一章讲了出荷传票的总结,以及出荷相关的其他知识,比如出荷控制,出荷传票登录的各种Tr-cd,Picking场所的决定,出荷传票的变更等内容。 SAP SD学习笔记12 - 出荷传票总结,出荷控制(出荷Type,出…

IDEA优雅debug

目录 引言一、断点分类🎄1.1 行断点1.2 方法断点1.3 属性断点1.4 异常断点1.5 条件断点1.6 源断点1.7 多线程断点1.8 Stream断点 二、调试动作✨三、Debug高级技巧🎉3.1 watch3.2 设置变量3.3 异常抛出3.4 监控JVM堆大小3.5 数组过滤和筛选 引言 使用ID…

MyBatisPlus(Spring Boot版)的基本使用

1. 初始化项目 1.1. 配置application.yml spring:# 配置数据源信息datasource:# 配置数据源类型type: com.zaxxer.hikari.HikariDataSource# 配置连接数据库信息driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis_plus?characterEncodi…

串口DMA接收不定长数据

STM32F767—>串口通信接收不定长数据的处理方法_stm32串口超时中断-CSDN博客 STM32-HAL库串口DMA空闲中断的正确使用方式解析SBUS信号_stm32 hal usart2 dma-CSDN博客 #define USART1_RxBuffSize 100 extern DMA_HandleTypeDef hdma_usart1_rx; //此处声明的变量在…

【Linux】进程字段、环境变量与进程地址空间

🌈 个人主页:谁在夜里看海. 🔥 个人专栏:《C系列》《Linux系列》《算法系列》 ⛰️ 丢掉幻想,准备斗争 目录 一、查看进程字段 1.字段说明 2.进程优先级 二、环境变量 1.概念 2.指令与PATH 3.环境变…

无人机场景 - 目标检测数据集 - 车辆检测数据集下载「包含VOC、COCO、YOLO三种格式」

数据集介绍:无人机场景车辆检测数据集,真实场景高质量图片数据,涉及场景丰富,比如无人机场景城市道路行驶车辆图片、无人机场景城市道边停车车辆图片、无人机场景停车场车辆图片、无人机场景小区车辆图片、无人机场景车辆遮挡、车…

【C++】vector 类模拟实现:探索动态数组的奥秘

🌟 快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。🌟 如果你对string,vector还存在疑惑,欢迎阅读我之前的作品 : 之前文章🔥&#x1f52…

小程序-基于java+SpringBoot+Vue的驾校预约平台设计与实现

项目运行 1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

初识算法 · 模拟(1)

目录 前言: 替换所有的问号 题目解析 算法原理 算法编写 提莫攻击 题目解析 算法原理 算法编写 外观数列 题目解析 算法原理 算法编写 前言: ​本文的主题是模拟,通过三道题目讲解,一道是提莫攻击,一道是…

使用 Vue 和 Create-Vue 构建工程化前端项目

目录 前言1. 工程化的意义与 Vue 的生态支持2. 搭建 Vue 工程化项目2.1 环境准备2.2 使用 create-vue 创建项目2.2.1 初始化项目2.2.2 安装依赖2.2.3 本地运行 3. Vue 项目的目录结构解析4. Vue 开发流程详解4.1 项目入口与根组件4.1.1 main.js 的作用4.1.2 App.vue 的结构 4.2…

Android中的AMS(Activity Manager Service)详解

Android中的AMS(Activity Manager Service)详解 AMS (Activity Manager Service) 是 Android 系统中非常核心的服务之一,它负责管理应用程序的生命周期、任务栈、进程、广播、服务等功能。AMS 是整个 Android Framework 的调度中心&#xff…

31.3 XOR压缩和相关的prometheus源码解读

本节重点介绍 : xor 压缩value原理xor压缩过程讲解xor压缩prometheus源码解读xor 压缩效果 xor 压缩value原理 原理:时序数据库相邻点变化不大,采用异或压缩float64的前缀和后缀0个数 xor压缩过程讲解 第一个值使用原始点存储计算和前面的值的xor 如果XOR值为0&…

UNIAPP发布小程序调用讯飞在线语音合成+实时播报

语音合成能够将文字转化为自然流畅的人声,提供100发音人供您选择,支持多语种、多方言和中英混合,可灵活配置音频参数。广泛应用于新闻阅读、出行导航、智能硬件和通知播报等场景。 在当下大模型火爆的今日,语音交互页离不开语音合…

【蓝牙协议栈】【BLE】【BAS】精讲蓝牙电池服务

1. 蓝牙电池服务(Bluetooth Battery Service)概念 蓝牙电池服务是蓝牙设备与其他设备通信时用于报告其剩余电池电量的标准服务。它让用户能够随时了解蓝牙设备(如无线耳机、智能手表、蓝牙鼠标/键盘等)的电池状态,从而方便地管理这些设备的续航与电源使用。 BAS通常用于在…