【goland如果使用xorm执行mysql的存储过程】
2023-12-13 18:44:26
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)
BEGIN
SET out_param = in_param + 10;
END
go代码实现
package main
import (
"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)
BEGIN
SET 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
}
// 打印输出参数的值,应该是20
fmt.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)
BEGIN
WITH RECURSIVE indirect_invites AS (
SELECT inviter_id, invitee_id
FROM user_invitation_relationship
WHERE inviter_id = InputInviterID
UNION ALL
SELECT ir.inviter_id, ir.invitee_id
FROM user_invitation_relationship ir
INNER JOIN indirect_invites ii ON ii.invitee_id = ir.inviter_id
)
SELECT DISTINCT invitee_id
FROM indirect_invites
WHERE invitee_id NOT IN (
SELECT invitee_id
FROM user_invitation_relationship
WHERE 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()
// 调用存储过程并将结果保存到 results
err := 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 []int64
for _, result := range results {
inviteeIds = append(inviteeIds, result.InviteeID)
}
return inviteeIds, nil
}
func GetIndirectInvitees(inviterID int64) ([]int64, error) {
var inviteeIds []int64
session := 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))
BEGIN
SELECT contact.user_id,
contact.real_name,
contact.age,
contact.phone_number,
contact.home_address AS address,
contact.create_time
FROM contact
WHERE contact.real_name = i_name;
END;
-- 调用执行存储过程
call query_contact1('Jerry')
go代码执行存储过程
package main
import (
"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 ContactResult
session := 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 datasource
import (
"PsycheEpic/src/config"
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/go-xorm/xorm"
"log"
)
var (
db *sql.DB
Engine *xorm.Engine
)
func InitMysql() {
fmt.Println("InitMysql....")
// xorm 连接数据库
var err error
Engine, 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 config
import (
"encoding/json"
"github.com/patrickmn/go-cache"
"os"
"time"
)
var (
Conf *AppConfig
CacheCode = cache.New(3*time.Hour, 15*time.Second)
)
type AppConfig struct {
AppName string `json:"app_name"` //项目名称 no-name
DBname string `json:"db_name"` //数据库名称 test_schema
DBserver string `json:"db_server"` //mysql域名
Mode string `json:"mode"`
Mysql_UserName string `json:"mysql_username"` //mysql用户名 root
Mysql_PWD string `json:"mysql_pwd"` //mysql密码 root
MysqlPort 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.File
var err error
if 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 = &conf
return &conf
}
json
{
"app_name": "no-name",
"db_name" : "nexthuman",
"db_server" : "localhost",
"mode": "dev",
"mysql_port": "3306",
"mysql_username" : "root",
"mysql_pwd" : "822198gxq!",
}
文章来源:https://blog.csdn.net/m0_46168848/article/details/134978846
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!