使用前阅读
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.sql; !!! ERROR
--[2]copy /PATH/TO/procedure.sql 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("mysql", 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
}
todo 完善该wiki