GinVueAdmin源码分析3-整合MySQL
目录
- 文件结构
- 数据库准备
- 配置文件处理
- config.go
- db_list.go
- gorm_mysql.go
- system.go
- 初始化数据库
- gorm.go
- gorm_mysql.go
- 开始初始化
- 测试数据库
- 定义实体类 User
- service
- api
- 开始测试!
文件结构
本文章将使用到上一节创建的 CommonService 接口,用于测试连接数据库状况,当然您也可以自制简单接口作为测试,不会影响整体工作流程!
下方树状图为最终项目结构
文件夹 api 与 service 助力数据库查询请求
initialize/gorm.go
初始化 GORM
initialize/gorm_mysql.go
执行 MySQL 数据库对应的初始化过程
user.go
一个实体类
│ config.yaml
│ go.mod
│ go.sum
│ main.go
│
├─api
│ │ enter.go
│ │
│ ├─example
│ └─system
│ api_common.go
│ enter.go
│
├─config
│ config.go
│ db_list.go
│ gorm_mysql.go
│ jwt.go
│ local.go
│ system.go
│
├─core
│ constant.go
│ server.go
│ viper.go
│
├─global
│ global.go
│
├─initialize
│ │ gorm.go
│ │ gorm_mysql.go
│ │ router.go
│ │
│ └─internal
│ gorm.go
│
├─model
│ user.go
│
├─router
│ │ enter.go
│ │
│ ├─example
│ └─system
│ enter.go
│ sys_common.go
│
└─service
之后回到项目根目录,打开命令行,输入指令安装 MySQL 驱动:
go get -u gorm.io/driver/mysql
数据库准备
这是我本地使用的数据库参数:
username:root
password:123456
dbname:golang
这是数据库“golang”中的数据表 user 的数据,注意到有四个属性
来到 go 项目中,根据上述参数,打开 config.yaml
,添加 mysql 配置
(这里为了便于大家操作,省去了源码中的注册 zap 的部分)
同时添加 system
对象,内含一个 db-type
属性,用来定义我们希望后端链接的数据库类型
system:db-type: "mysql"mysql:path: "localhost"port: "3306"config: ""db-name: "golang"username: "root"password: "123456"max-idle-conns: 10max-open-conns: 100
配置文件处理
由于我们为 config.yaml 添加了新的配置项,所以需要按照我们之前文章所属,为其配置指定的结构!
config.go
打开(如果你跟随上上节文章)或者新建文件 config/config.go
在主 config 入口添加 mysql 属性
type Server struct {...Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
}
db_list.go
新建文件 config/db_list.go
由于我们有可能需要支持多种类型的数据库(比如 PostgreSQL),所以最佳解决办法就是创建一个通用的数据库参数结构体
DSNProvider
接口用来给 GORM 提供 DSN
type DSNProvider interface {Dsn() string
}type GeneralDB struct {Path string `mapstructure:"path" json:"path" yaml:"path"` // 服务器地址:端口Port string `mapstructure:"port" json:"port" yaml:"port"` //:端口Config string `mapstructure:"config" json:"config" yaml:"config"` // 高级配置Dbname string `mapstructure:"db-name" json:"db-name" yaml:"db-name"` // 数据库名Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库用户名Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` //全局表前缀,单独定义TableName则不生效Singular bool `mapstructure:"singular" json:"singular" yaml:"singular"` //是否开启全局禁用复数,true表示开启Engine string `mapstructure:"engine" json:"engine" yaml:"engine" default:"InnoDB"` //数据库引擎,默认InnoDBMaxIdleConns int `mapstructure:"max-idle-conns" json:"max-idle-conns" yaml:"max-idle-conns"` // 空闲中的最大连接数MaxOpenConns int `mapstructure:"max-open-conns" json:"max-open-conns" yaml:"max-open-conns"` // 打开到数据库的最大连接数
}
gorm_mysql.go
新建文件 gorm_mysql.go
在这里定义 mysql 结构体,直接使用通用数据库参数结构体 GeneralDB 即可
然后于此实现接口 DSNProvider
,构造 DSN
type Mysql struct {GeneralDB `yaml:",inline" mapstructure:",squash"`
}func (m *Mysql) Dsn() string {return m.Username + ":" + m.Password + "@tcp(" + m.Path + ":" + m.Port + ")/" + m.Dbname + "?" + m.Config
}
system.go
打开文件 config/system.go
老样子,为 db_type 配置对应结构体内容
type System struct {DbType string `mapstructure:"db-type" json:"db-type" yaml:"db-type"`
}
初始化数据库
gorm.go
新建文件 initialize/gorm.go
此处的逻辑很简单,即通过全局变量获取 db_type 属性,得知开发者想要用那种数据库;
由于我们只会用到 MySQL,故这里的判断就都启动 mysql 了
GormMysql
目前处于飘红状态,因为还没有定义,下面我们将为其定义初始化 MySQL 的方法
import ("ginlogin/global""gorm.io/gorm"
)func Gorm() *gorm.DB {switch global.G_CONFIG.System.DbType {case "mysql":return GormMysql()default:return GormMysql()}
}
gorm_mysql.go
新建文件 initialize/gorm_mysql.go
具体通过 GORM 链接 mysql 的过程相信大家也很熟悉,这里就不多费口舌了,直接看注释吧!
import ("fmt""ginlogin/global""gorm.io/driver/mysql""gorm.io/gorm"
)// 初始化mysql方法,返回一个gorm.DB引用
func GormMysql() *gorm.DB {// 第一步// 全局变量获取config中定义的mysql参数// 判断如果不急于数据库名,直接返回nil表示初始化数据库失败info := global.G_CONFIG.Mysqlif info.Dbname == "" {return nil}// 第二步// 构造mysqlConfigmysqlConfig := mysql.Config{DSN: info.Dsn(),DefaultStringSize: 191,SkipInitializeWithVersion: false,}// 第三步// gorm.Open连接到数据库,并处理错误if db, err := gorm.Open(mysql.New(mysqlConfig)); err != nil {fmt.Println("完蛋,连接不上数据库!!!")return nil} else {// 如果成功链接,设置好连接池啥的,就可以返回db了db.InstanceSet("gorm:table_options", "ENGINE="+info.Engine)sqlDB, _ := db.DB()sqlDB.SetMaxIdleConns(info.MaxIdleConns)sqlDB.SetMaxOpenConns(info.MaxOpenConns)return db}
}
开始初始化
哎?这还没完,你还要调用初始化方法!
打开 main.go,添加如下代码,调用 GORM 初始化方法
func main() {// 初始化数据库DBglobal.G_DB = initialize.Gorm()...
}
此处关于整合 mysql 的部分已经完结了,下面将是测试数据库的内容,您可以直接略过
测试数据库
定义实体类 User
新建文件 model/user.go
根据开头所述 user 表,故可定义如下实体类
type User struct {Id int `json:"id"`Username string `json:"username"`Password string `json:"password"`Role int `json:"role"`
}// 显式指定表名
func (User) TableName() string {return "user"
}
service
打开文件 service/system/service_common.go
service 层内简单实现了查询整张表的功能,并作了错误处理
type CommonService struct{}func (s *CommonService) CreateApi(c *gin.Context) (err error) {// 调用Find方法查询表,将查询成功与否的结果存到res变量var userList []model.Userres := global.G_DB.Find(&userList)// 判断res是否出现了错误if errors.Is(res.Error, gorm.ErrRecordNotFound) {return errors.New("找不到这个元素")}// 如果没错,那就返回数据c.JSON(http.StatusOK, gin.H{"data": userList,})// 给api层传递一个errorreturn res.Error
}
api
打开文件 api/system/api_common.go
很简单,调用 service,然后在 api
中处理错误并返回 JSON
数据(这一步也可以直接全部写在 service
层里,此时就可以把该 api 层看做是 springboot
中的 controller
层了!)
import ("github.com/gin-gonic/gin""net/http"
)type CommonApi struct{}func (s *CommonApi) CreateApi(c *gin.Context) {err := commonService.CreateApi(c)if err != nil {c.JSON(http.StatusBadRequest, gin.H{"status": err.Error(),})}
}
开始测试!
万事俱备,只欠东风,打开你的 postman|apifox|apipost,请求以下看看结果吧!
相关文章:

GinVueAdmin源码分析3-整合MySQL
目录文件结构数据库准备配置文件处理config.godb_list.gogorm_mysql.gosystem.go初始化数据库gorm.gogorm_mysql.go开始初始化测试数据库定义实体类 Userserviceapi开始测试!文件结构 本文章将使用到上一节创建的 CommonService 接口,用于测试连接数据库…...
大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——MapReduce开发总结
在编写MapReduce程序时,需要考虑如下几个方面: 1、输入数据接口:InputFormat 默认使用的实现类是:TextInputFormatTextInputFormat的功能逻辑是:一次读一行文本,然后将该行的起始偏移量作为key࿰…...

requests---(4)发送post请求完成登录
前段时间写过一个通过cookies完成登录,今天我们写一篇通过post发送请求完成登录豆瓣网 模拟登录 1、首先找到豆瓣网的登录接口 打开豆瓣网站的登录接口,请求错误的账号密码,通过F12或者抓包工具找到登录接口 通过F12抓包获取到请求登录接口…...

Python抓取数据具体流程
之前看了一段有关爬虫的网课深有启发,于是自己也尝试着如如何过去爬虫百科“python”词条等相关页面的整个过程记录下来,方便后期其他人一起来学习。 抓取策略 确定目标:重要的是先确定需要抓取的网站具体的那些部分,下面实例是…...

【Python学习笔记】第二十四节 Python 正则表达式
一、正则表达式简介正则表达式(regular expression)是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特…...

数字逻辑基础:原码、反码、补码
时间紧、不理解可以只看这里的结论 正数的原码、反码、补码相同。等于真值对应的机器码。 负数的原码等于机器码,反码为原码的符号位不变,其余各位按位取反。补码为反码1。 三种码的出现是为了解决计算问题并简化电路结构。 在原码和反码中,存…...
有限差分法-差商公式及其Matlab实现
2.1 有限差分法 有限差分法 (finite difference method)是一种数值求解偏微分方程的方法,它将偏微分方程中的连续变量离散化为有限个点上的函数值,然后利用差分逼近导数,从而得到一个差分方程组。通过求解差分方程组,可以得到原偏微分方程的数值解。 有限差分法是一种历史…...
高校就业信息管理系统
1引言 1.1编写目的 1.2背景 1.3定义 1.4参考资料 2程序系统的结构 3登录模块设计说明一 3.1程序描述 3.2功能 3.3性能 3.4输人项 3.5输出项 3.6算法 3.7流程逻辑 3.8接口 3.10注释设计 3.11限制条件 3.12测试计划 3.13尚未解决的问题 4注册模块设计说明 4.…...

【Java|golang】2373. 矩阵中的局部最大值
给你一个大小为 n x n 的整数矩阵 grid 。 生成一个大小为 (n - 2) x (n - 2) 的整数矩阵 maxLocal ,并满足: maxLocal[i][j] 等于 grid 中以 i 1 行和 j 1 列为中心的 3 x 3 矩阵中的 最大值 。 换句话说,我们希望找出 grid 中每个 3 x …...

根据指定函数对DataFrame中各元素进行计算
【小白从小学Python、C、Java】【计算机等级考试500强双证书】【Python-数据分析】根据指定函数对DataFrame中各元素进行计算以下错误的一项是?import numpy as npimport pandas as pdmyDict{A:[1,2],B:[3,4]}myDfpd.DataFrame(myDict)print(【显示】myDf)print(myDf)print(【…...
【蓝桥杯集训·每日一题】AcWing 3502. 不同路径数
文章目录一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解三、知识风暴一、题目 1、原题链接 3502. 不同路径数 2、题目描述 给定一个 nm 的二维矩阵,其中的每个元素都是一个 [1,9] 之间的正整数。 从矩阵中的任意位置出发…...

Java - 数据结构,二叉树
一、什么是树 概念 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点: 1、有…...

模拟QQ登录-课后程序(JAVA基础案例教程-黑马程序员编著-第十一章-课后作业)
【案例11-3】 模拟QQ登录 【案例介绍】 1.案例描述 QQ是现实生活中常用的聊天工具,QQ登录界面看似小巧、简单,但其中涉及的内容却很多,对于初学者练习Java Swing工具的使用非常合适。本案例要求使用所学的Java Swing知识,模拟实…...

【壹】嵌入式系统硬件基础
随手拍拍💁♂️📷 日期: 2023.2.28 地点: 杭州 介绍: 日子像旋转毒马🐎,在脑海里转不停🤯 🌲🌲🌲🌲🌲 往期回顾 🌲🌲🌲…...

当参数调优无法解决kafka消息积压时可以这么做
今天的议题是:如何快速处理kafka的消息积压 通常的做法有以下几种: 增加消费者数增加 topic 的分区数,从而进一步增加消费者数调整消费者参数,如max.poll.records增加硬件资源 常规手段不是本文的讨论重点或者当上面的手段已经使…...

Java线程池源码分析
Java 线程池的使用,是面试必问的。下面我们来从使用到源码整理一下。 1、构造线程池 通过Executors来构造线程池 1、构造一个固定线程数目的线程池,配置的corePoolSize与maximumPoolSize大小相同, 同时使用了一个无界LinkedBlockingQueue存…...

手撕八大排序(下)
目录 交换排序 冒泡排序: 快速排序 Hoare法 挖坑法 前后指针法【了解即可】 优化 再次优化(插入排序) 迭代法 其他排序 归并排序 计数排序 排序总结 结束了上半章四个较为简单的排序,接下来的难度将会大幅度上升&…...

SAP 详细解析SCC4
事务代码:SCC4,选择一个客户端,点击进入,如图: 一、客户端角色 客户控制:客户的角色(生产性,测试,...) 此属性表示 R/3 系统中的客户端角色。其中可能包括…...

java异常分类和finally代码块中return语句的影响
首先看一下java中异常相关类的继承关系: 引用 1、分类 异常可以分为受查异常和非受查异常,Error和RuntimeException及其所有的子类都是非受查异常,其他的是受查异常。 两者的区别主要在: 受检的异常是由编译器(编译…...

【链表OJ题(二)】链表的中间节点
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:数据结构 🎯长路漫漫浩浩,万事皆有期待 文章目录链表OJ题(二)1. 链表…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...