使用前阅读
ref-1:问题来源 [支付系统数据库设计的关键问题 ]
ref-2:[Golang 用go-sql-driver 调用MySQL存储过程时的问题排查]
编辑文件src/github.com/go-sql-driver/MysqL/packets.go文件,在函数writeAuthPacket(cipher []byte) (大约在210行)的客户端标志位处添加下面两个标志:
func (mc *MysqLConn) writeAuthPacket(cipher []byte) error { // Adjust client flags based on server support clientFlags := clientProtocol41 | clientSecureConn | clientLongPassword | clientTransactions | clientLocalFiles | **clientMultiStatements | // 添加这行 clientMultiResults |** //再添加这行 mc.flags&clientLongFlag if mc.cfg.clientFoundRows { clientFlags |= clientFoundRows }
一、MysqL创建存储过程
-- 单行执行以下语句 SET NAMES utf8; -- dsp_settle数据库 USE dsp_settle; DROP PROCEDURE IF EXISTS settle_balance_deduction; -- [1]设置分隔符为// DELIMITER // --[2] 执行source /path/to/procedure.; !!! ERROR --[2] /PATH/TO/procedure. to console and enter --[3]还原分隔符 DELIMITER ; --[4]调用示例 call settle_balance_deduction(5372539,1234,100,@out_status); select @out_status; -- 其他常用操作 -- 调研存储过程 call procedure_name(parameters); -- 查询存储过程 SHOW PROCEDURE STATUS; -- 显示一个存储过程详情 SHOW CREATE PROCEDURE procedure_name; -- 删除存储过程 DROP PROCEDURE procedure_name;
存储过程代码
-- 创建存储过程 CREATE PROCEDURE settle_balance_deduction (in_userID bigint,in_planID INT,in_money INT,OUT out_status INT ) BEGIN -- 变量 用户实际余额 DECLARE account_balance INT; START TRANSACTION; SELECT balance INTO account_balance FROM dsp_settle.user_balance WHERE userId = in_userID AND status = 0 AND isDelete = 0 FOR UPDATE; IF account_balance >= in_money THEN -- 扣费操作 UPDATE user_balance SET balance = balance - in_money,opUserId = 1001 WHERE userId = in_userID; -- 扣费记录 INSERT INTO dsp_settle.charge_record(userId,planId,charge,opUserId,addTime) VALUES (in_userID,in_planID,in_money, 1001,Now()); -- 提交事务处理 COMMIT; -- 返回结果状态1 SET out_status = 1; ELSE -- 余额小于扣费额,不操作 ROLLBACK; -- 返回结果状态0 SET out_status = 0; END IF; END //
Go调用存储过程代码,亲测可用
package balance import ( "database/sql" _ "github.com/go-sql-driver/MysqL" "strconv" "fmt" ) const ( //DSN = "root:tongzhen@tcp(127.0.0.1:3306)" DSN = "root:123456@tcp(10.48.23.51:8086)" DB_DSP = "dsp" DB_SETTLE = "dsp_settle" ) //扣费结算 func Settle(userID int,planID int,charge int) int{ db,err := sql.Open(,DSN + "/" + DB_SETTLE) if err != nil { panic(err.Error()) } defer db.Close() handle,err := db.Prepare("CALL dsp_settle.settle_balance_deduction(?,?,@out_status)") if err != nil { panic(err.Error()) } defer handle.Close() //call procedure var result sql.Result result,err = handle.Exec(userID,planID,charge) if err != nil { panic(err.Error()) } fmt.Println(result) var sql string = "SELECT @out_status as ret_status" selectInstance,err := db.Prepare(sql) if err != nil { panic(err.Error()) } defer selectInstance.Close() var ret_status int err = selectInstance.QueryRow().Scan(&ret_status) if err != nil { panic(err.Error()) } fmt.Println(ret_status) return ret_status }t 完善该wiki