【goland如果使用xorm执行mysql的存储过程】

goland如果使用xorm执行mysql的存储过程

需求背景

存在用户表和用户邀请关系表,当用户A邀请用户B,则B用户为A用户直接邀请的人;B用户邀请了C用户,则C用户就是A用户的间接邀请人。

如何查询当前用户间接邀请的注册用户有那些?

需求分析

  • 需要使用递归查询间接邀请的用户有那些,将其id放到一个数组中。
  • 将这个递归查询的SQL转换成一个存储过程,使用xorm执行mysql的存储过程;这样操作避免SQL注入。

xorm执行mysql的存储过程的demo示例

存储过程如下

  • 创建一个存储过程,传入一个int类型的参数,返回一个int类型的参数
CREATE PROCEDURE add_ten(IN in_param INT, OUT out_param INT)BEGINSET out_param = in_param + 10;END

go代码实现

package mainimport ("PsycheEpic/src/config""PsycheEpic/src/datasource""fmt"_ "github.com/go-sql-driver/mysql"
)// 当然这里也可以定义一个结构体,用于接收存储过程的输出的参数
/*
type Result struct {OutParam int `xorm:"out_param"`
}
*/func main() {config.InitConfig()datasource.InitMysql()// 创建一个存储过程,接收一个输入参数in_param,返回一个输出参数out_param// 存储过程的逻辑是将输入参数加10后赋值给输出参数sql := `CREATE PROCEDURE add_ten(IN in_param INT, OUT out_param INT)BEGINSET out_param = in_param + 10;END`_, err := datasource.Engine.Exec(sql)if err != nil {fmt.Println(err)return}// 调用存储过程,传入一个输入参数10,使用一个Result结构体变量接收输出参数var out_param int_, err = datasource.Engine.Exec("CALL add_ten(?,  @out_param)", 10)if err != nil {fmt.Println(err)return}// 从MySQL中获取存储过程的输出参数_, err = datasource.Engine.SQL("SELECT @out_param").Get(&out_param)if err != nil {fmt.Println(err)return}// 打印输出参数的值,应该是20fmt.Println(out_param)}
  • 【注意】如果存储过程中没有查询输出参数结果的SELECT语句,需要在代码中执行查询操作

    • // 从MySQL中获取存储过程的输出参数_, err = datasource.Engine.SQL("SELECT @out_param").Get(&out_param)if err != nil {fmt.Println(err)return}
      

需求实现

存储过程的SQL如下:
DELIMITER //
CREATE PROCEDURE GetIndirectInvites(IN InputInviterID INT)
BEGINWITH RECURSIVE indirect_invites AS (SELECT inviter_id, invitee_idFROM user_invitation_relationshipWHERE inviter_id = InputInviterIDUNION ALLSELECT ir.inviter_id, ir.invitee_idFROM user_invitation_relationship irINNER JOIN indirect_invites ii ON ii.invitee_id = ir.inviter_id)SELECT DISTINCT invitee_idFROM indirect_invitesWHERE invitee_id NOT IN (SELECT invitee_idFROM user_invitation_relationshipWHERE inviter_id = InputInviterID);
END //
DELIMITER ;
  • 调用执行存储过程
call GetIndirectInvites(1)

代码实现

// GetIndirectInvitees 通过存储过程获取间接邀请人// Invitee 是一个用于存储存储过程返回结果的结构体
type Invitee struct {InviteeID int64 `xorm:"invitee_id"`
}// GetIndirectInvitees 通过存储过程获取间接邀请人
func GetIndirectInvitees(inviterID int64) ([]int64, error) {// 创建用于存储结果的切片var results []Invitee// 使用Session来执行存储过程session := datasource.Engine.NewSession()defer session.Close()// 调用存储过程并将结果保存到 resultserr := session.SQL("CALL GetIndirectInvites(?)", inviterID).Find(&results)if err != nil {// 注意这里不再是 log.Fatalf,因为我们需要返回错误而不是立即退出程序return nil, errors.New("调用查询间接邀请人的存储过程报错: " + err.Error())}// 如果结果数组为空,则返回一个空数组而不是错误if len(results) == 0 {return []int64{}, nil}// 将结果转换为 int64 数组var inviteeIds []int64for _, result := range results {inviteeIds = append(inviteeIds, result.InviteeID)}return inviteeIds, nil
}func GetIndirectInvitees(inviterID int64) ([]int64, error) {var inviteeIds []int64session := datasource.Engine.NewSession()defer session.Close()err := session.SQL("CALL GetIndirectInvites(?)", inviterID).Find(&inviteeIds)if err != nil {return nil, errors.New("调用查询间接邀请人的存储过程出错: " + err.Error())}return inviteeIds, nil
}

示例二

SQL存储过程如下

CREATE PROCEDURE query_contact(IN i_name VARCHAR(10))
BEGINSELECT contact.user_id, contact.real_name, contact.age, contact.phone_number, contact.home_address AS address, contact.create_time FROM contactWHERE contact.real_name = i_name;
END;
-- 调用执行存储过程
call  query_contact1('Jerry')
-- 查看所有的存储过程
SHOW PROCEDURE STATUS;
-- 查看指定的存储过程
SHOW CREATE PROCEDURE query_contact;-- 删除指定的存储过程
DROP PROCEDURE IF EXISTS query_contact;
DROP PROCEDURE IF EXISTS GetIndirectInvites;

go代码执行存储过程

package mainimport ("PsycheEpic/src/config""PsycheEpic/src/datasource""fmt"_ "github.com/go-sql-driver/mysql""log"
)type Contact struct {UserId      int    `json:"user_id" xorm:"user_id"`Name        string `json:"name" jorm:"real_name" xorm:"real_name"`Age         int    `json:"age" xorm:"age"`PhoneNumber string `json:"phone_number" xorm:"phone_number"`HomeAddress string `json:"home_address" xorm:"home_address"`CreateTime  string `json:"create_time" xorm:"create_time"`
}type ContactResult struct {UserID      int    `xorm:"user_id"`RealName    string `xorm:"real_name"`Age         int    `xorm:"age"`PhoneNumber string `xorm:"phone_number"`Address     string `xorm:"address"`CreateTime  string `xorm:"create_time"`
}func QueryContact(name string) (*ContactResult, error) {var result ContactResultsession := datasource.Engine.NewSession()// 由于 xorm 不支持 OUT 参数,我们直接获取返回的结果集_, err := session.SQL("CALL query_contact(?)", name).Get(&result)if err != nil {return nil, err}return &result, nil
}func main() {//读取参数配置config.InitConfig()//执行数据库初始化datasource.InitMysql()// 调用函数name := "Jerry"contact, err := QueryContact(name)if err != nil {log.Fatal(err)}fmt.Printf("Result: %+v\n", contact)
}

xorm的mysql初始化函数

package datasourceimport ("PsycheEpic/src/config""database/sql""fmt"_ "github.com/go-sql-driver/mysql""github.com/go-xorm/xorm""log"
)var (db     *sql.DBEngine *xorm.Engine
)func InitMysql() {fmt.Println("InitMysql....")// xorm 连接数据库var err errorEngine, err = xorm.NewEngine("mysql", config.Conf.Mysql_UserName+":"+config.Conf.Mysql_PWD+"@tcp(127.0.0.1:"+config.Conf.MysqlPort+")/"+config.Conf.DBname+"?charset=utf8")fmt.Println(" ============== 【xorm 连接数据库】 =====================   ")println("xorm 连接数据库,Engine: ", Engine)fmt.Println(" ============== 【xorm 连接数据库】 =====================   ")if err != nil {log.Println("数据库连接失败:", err)fmt.Println("数据库连接失败:", err)return}}

读取json配置

package configimport ("encoding/json""github.com/patrickmn/go-cache""os""time"
)var (Conf      *AppConfigCacheCode = cache.New(3*time.Hour, 15*time.Second)
)type AppConfig struct {AppName string `json:"app_name"` //项目名称 no-nameDBname   string `json:"db_name"`   //数据库名称 test_schemaDBserver string `json:"db_server"` //mysql域名Mode           string `json:"mode"`Mysql_UserName string `json:"mysql_username"` //mysql用户名 rootMysql_PWD      string `json:"mysql_pwd"`      //mysql密码 rootMysqlPort      string `json:"mysql_port"`     //mysql启动端口Port string `json:"port"` //项目启动端口Md5Salt string `json:"md5_salt"`
}func InitConfig() *AppConfig {file, err := os.Open("./config.json")/*var file *os.Filevar err errorif runtime.GOOS == "linux" {file, err = os.Open("./config.json")} else {file, err = os.Open("src/config.json")}*/if err != nil {println("error is :", err)}decoder := json.NewDecoder(file)conf := AppConfig{}err = decoder.Decode(&conf)if err != nil {println("error is :", err)}Conf = &confreturn &conf}

json

{"app_name": "no-name","db_name" : "nexthuman","db_server" : "localhost","mode": "dev","mysql_port": "3306","mysql_username" : "root","mysql_pwd" : "822198gxq!",}

【补充】
mysql的存储过程的基本语法:
MySQL 中存储过程的基本语法如下所示:

创建存储过程

CREATE PROCEDURE procedure_name(parameters)[characteristics]routine_body
  • procedure_name:存储过程的名称。
  • parameters:存储过程的参数列表,可以包括输入参数、输出参数和输入输出参数。
  • characteristics:存储过程的特性,例如安全性、SQL 模式等。可以包括 DETERMINISTICLANGUAGE SQL 等。
  • routine_body:存储过程的实际逻辑代码部分。

存储过程参数

参数可以是输入参数、输出参数或者输入输出参数。

  • 输入参数:在存储过程调用时传入值给存储过程使用。
  • 输出参数:存储过程执行完毕后传出值给调用方。
  • 输入输出参数:在存储过程调用时传入值,并且在存储过程执行完毕后传出值给调用方。

存储过程实例

下面是一个简单的示例,创建一个简单的存储过程来获取指定用户的信息:

DELIMITER //CREATE PROCEDURE GetUserInformation (IN userId INT, OUT userName VARCHAR(50), OUT userAge INT)
BEGINSELECT name, age INTO userName, userAge FROM users WHERE id = userId;
END//DELIMITER ;

调用存储过程

调用存储过程的语法如下:

CALL procedure_name(argument1, argument2, ...);

在这个示例中,假设我们已经有一个名为 GetUserInformation 的存储过程,我们可以通过以下方式调用它:

CALL GetUserInformation(123, @name, @age);

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

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

相关文章

ROS2 学习08 导航Nav2:简介、安装、测试效果、错误处理

1、简介 在ROS2中自动导航使用Nav2来实现。 Nav2 使用几个独立的模块化服务,通过 ROS 2接口(例如动作服务器或服务)与行为树 (BT) 通信。 Nav2 输入包括:TF转换、一个地图源、一个行为树 (BT) XML 文件和相关的传感器数据源; Nav…

每日学习打卡

文章目录 12月份学习:牛客网刷题 12月份学习:牛客网刷题 12/11 周一12/12 周二12/13 周三12/14 周四12/15 周五牛客网1_非技术快速入门:26-39 ✅牛客网1_非技术快速入门:复习1-39 ✅牛客网2_SQL基础进阶:1-18牛客网2_…

C语言好题分享七(三数之和)

❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载,请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤ 三数之和 题目来源LeetCode:刷题传送门 题目:给你一个整数数组 nums ,判断…

EasyRecovery2024专业版下载安装步骤图文详细教程

EasyRecovery是一款操作安全、价格便宜、用户自主操作的非破坏性的只读应用程序,它不会往源驱上写任何东西,也不会对源驱做任何改变。它支持从各种各样的存储介质恢复删除或者丢失的文件,其支持的媒体介质包括:硬盘驱动器、光驱、…

2-分布式存储之glusterfs

任务背景 实现了远程的存储共享(NAS或SAN)后, 公司业务发展迅速, 存储空间还需要增大。使用NAS或SAN都不方便扩容,NAS可以增加新的挂载目录, SAN可以增加新的硬盘,但我们希望直接在原来挂载的业务目录上实现在线扩容,数据体量越来越大, 这个…

ChatGLM3-6B和langchain知识库阿里云部署

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、ChatGLM3-6B部署搭建环境部署GLM3 二、Chatglm2-6blangchain部署本地知识库三、Tips四、总结 前言 提示:这里可以添加本文要记录的大概内容&am…

ffmpeg从视频文件中截取一段视频

处理 ffmpeg -i ./【直播】2023-10-08\ 二〇二三澳洲淨宗學院護國息災三時繫念法會.mp4 -ss 02:43:12 -to 03:03:00 -vcodec copy -acodec copy 阿弥陀佛.mp4参考解释: -i:输入的源文件;-ss hh:mm:ss -to hh:mm:ss:从源视频的某个时间点到某个时间点&a…

7个Js async/await高级用法

前端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库 7个Js async/await高级用法 JavaScript的异步编程已经从回调(Callback)演进到Promise,再到如今广泛使用的async/await语法。后者不仅让异步…

被央视报道过的AIGC产品-贝塔创作(BetaCreator)使用指南

产品地址:betacreator.com 真人图 人台图 商品图 商品变色 建议使用浅色服装进行变色,效果更好 如果没有浅色服装,可以先把服装颜色变为白色

视频剪辑必备的6个免费素材网站

视频剪辑需要用到很多音效、视频、图片等素材,下面我就分享几个剪辑必备的免费视频素材网站,赶紧收藏起来~ 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYwNDUx 菜鸟图库虽然是个设计素材网站,但除了设计类素材之外还有很多视频、…

2697. 字典序最小回文串

我的解法&#xff1a; 将字符串反转开始比较。 C class Solution { public:string makeSmallestPalindrome(string s) {string a s, b s;reverse(b.begin(), b.end());int n s.size();for (int i 0; i < n; i) {if (a[i] ! b[i]) {a[i] b[i] min(a[i], b[i]);a[n - …

python学习:浅拷贝与深拷贝详解

copy 一、 & is二、浅拷贝 & 深拷贝(一)、浅拷贝(二)、深拷贝 三、问题 一、’ ’ & ‘is’ ’ 和is是python对象比较常用的两种方式,简单来说,‘ ‘操作符比较对象之间的值是否相等,如 a b 而’is’操作符比较的是对象的身份标识是否相等,即它们是否是同一个…

Linux系统解决“Key was rejected by service”

Linux系统下加载驱动模块出现如上错误提示的原因为&#xff1a;此驱动未经过签名。 方法一、关闭Secure Boot 如果是物理机&#xff0c;需要开机进入BIOS&#xff0c;找到“Secure Boot”的选项&#xff0c;然后关闭。 如果是虚拟机&#xff0c;可以打开虚拟设置&#xff0c…

arthas(阿尔萨斯) 使用问题汇总

arthas 使用问题汇总 1、arthas查看不到java进程1.1、首先要保证你的环境变量配置是正确的1.2、jps 也看不到java进程 2、离线安装问题3、如何使用arthas 1、arthas查看不到java进程 1.1、首先要保证你的环境变量配置是正确的 java -verionjavac -version 都能正常显示 [rootd…

平面上点到直线的距离

文章目录 平面上点到直线的距离 平面上点到直线的距离 设坐标平面上有点 P ( x 1 , y 1 ) P(x_1,y_1) P(x1​,y1​)和直线 l : A x B y C 0 l:AxByC0 l:AxByC0, A , B A,B A,B不全为0点 P P P到直线 l l l的的距离的算法推导如下 作直线 m m m通过点 P ( x 1 , y 1 ) P(x_1…

上传文件Dubbo报错: Data length too large: xxxxx, max payload: 8388608

一、场景&#xff1a; 服务端是微服务&#xff0c;服务A有个上传图片的功能&#xff0c;需求是限制大小为10M&#xff0c;用户通过客户端把图片上传到服务A&#xff0c;A再调用服务B把文件上传至阿里oss。 功能实际上很简单&#xff0c;实现的代码如下&#xff1a; 服务A的Con…

快速准确翻译文件夹名:英文翻译成中文,文件夹批量重命名的技巧

在处理大量文件夹时&#xff0c;可能会遇到要将英文文件夹名翻译成中文的情况。同时也可能要批量重命名这些文件夹。今天一起来看下云炫文件管理器如何快速准确翻译文件夹名&#xff0c;进行批量重命名的技巧。 下图是文件夹名翻译前后的效果图。 英文文件夹名批量翻译成中文…

3Dmax快捷键大全,让你的创作飞起来!附赠3dmax工具箱插件,快来收藏吧!

你是否曾经在3Dmax中因为繁琐的操作而感到困扰&#xff1f; 今天&#xff0c;我将为大家带来一份精心整理的3Dmax常用快捷键宝典&#xff0c;让你在建模、材质编辑、动画制作等各个方面都能游刃有余&#xff0c;让你的创作飞起来&#xff01;&#xff01; &#x1f4a1; 选择与…

7-1 jmu-python-输入输出-处理不定行输入

7-1 jmu-python-输入输出-处理不定行输入 分数 15 作者 郑如滨 单位 集美大学 处理一段文字&#xff08;可能有很多行&#xff0c;行数不确定&#xff09;&#xff0c;输出每行包含的单词数(单词之间以空格或多个空格分隔)。 注意&#xff1a;处理的时候要忽略掉空行或者空格行…

27. 深度学习进阶 - 为什么RNN

文章目录 一个柯基的例子为什么RNN or CNN Hi&#xff0c;你好。我是茶桁。 这节课开始&#xff0c;我们将会讲一个比较重要的一种神经网络&#xff0c;它对应了咱们整个生活中很多类型的一种问题结构&#xff0c;它就是咱们的RNN网络。 咱们首先回忆一下&#xff0c;上节课咱…