wordpress网站维护,广州安全教育平台咨询电话,许昌做网站汉狮网络,津坤科技天津网站建设goland如果使用xorm执行mysql的存储过程
需求背景
存在用户表和用户邀请关系表#xff0c;当用户A邀请用户B#xff0c;则B用户为A用户直接邀请的人#xff1b;B用户邀请了C用户#xff0c;则C用户就是A用户的间接邀请人。
如何查询当前用户间接邀请的注册用户有那些当用户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;ENDgo代码实现
package mainimport (PsycheEpic/src/configPsycheEpic/src/datasourcefmt_ 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/configPsycheEpic/src/datasourcefmt_ github.com/go-sql-driver/mysqllog
)type Contact struct {UserId int json:user_id xorm:user_idName string json:name jorm:real_name xorm:real_nameAge int json:age xorm:agePhoneNumber string json:phone_number xorm:phone_numberHomeAddress string json:home_address xorm:home_addressCreateTime string json:create_time xorm:create_time
}type ContactResult struct {UserID int xorm:user_idRealName string xorm:real_nameAge int xorm:agePhoneNumber string xorm:phone_numberAddress string xorm:addressCreateTime 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 : Jerrycontact, err : QueryContact(name)if err ! nil {log.Fatal(err)}fmt.Printf(Result: %v\n, contact)
}
xorm的mysql初始化函数
package datasourceimport (PsycheEpic/src/configdatabase/sqlfmt_ github.com/go-sql-driver/mysqlgithub.com/go-xorm/xormlog
)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_PWDtcp(127.0.0.1:config.Conf.MysqlPort)/config.Conf.DBname?charsetutf8)fmt.Println( 【xorm 连接数据库】 )println(xorm 连接数据库,Engine: , Engine)fmt.Println( 【xorm 连接数据库】 )if err ! nil {log.Println(数据库连接失败:, err)fmt.Println(数据库连接失败:, err)return}}
读取json配置
package configimport (encoding/jsongithub.com/patrickmn/go-cacheostime
)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:modeMysql_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_bodyprocedure_name存储过程的名称。parameters存储过程的参数列表可以包括输入参数、输出参数和输入输出参数。characteristics存储过程的特性例如安全性、SQL 模式等。可以包括 DETERMINISTIC、LANGUAGE 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);