由于项目需要使用GO来调用mssql存储过程,所以不得已研究一下,整个过程是比较费劲的,因为本人还处于GO小白状态,公司项目是基于网狐的棋牌平台,网狐项目不得不说还是比较整洁清晰的,但是由于出道以来一直在用这套框架大概有7-8年时间太久了有点腻了,同时为了学习一下新技术新知识,最终选定用GO语言重写服务端。

为了顺利平稳移植重构,我决定分阶段进行首先重写协调服务器,因为本身协调服务器工作量是最小的,其次是登录服务器,最后是游戏服务器。

首先要解决两大问题,第一个网络通讯,第二个就是数据库,网络部分暂且不说已经解决,单说数据库部分,由于网狐服务端默认数据库的所有操作都是通过存储过程来执行,所以能以一个较为友好的调用方式是比较重要的,但是在探索过程中还是碰到好多问题,首先发现一篇很早的帖子https://blog.csdn.net/luomoshusheng/article/details/52445597但是失败了,中间也用过xorm这样的开源库,确实很强大但仍然无法顺利满足需求,只能从官方mssql驱动找方法,

以下是GO语言官方驱动

其中mssql驱动为

gofreetds实在C开源库TDS基础上实现的貌似对存错过程支持更加友好,且有较为完整的事例

但是C开源库TDS在windows下却不是很方便,对linux、macos支持应该没有问题,虽然在windows下编译通过了但是运行有些问题应该是依赖库的原因,所以暂时放弃,转看下一个纯GO的驱动go-mssqldb

同样对存错过程也是支持的,但是问题来了,给出的接口中获取存储过程的返回值以及获取返回结果集是在两个接口中分别实现的,也就是说要获取这两个值需要重复调用两次存储过程!以我小白的经验来说作者不太可能这样设计,奈何我研究半天没没能找出正确的调用方式,英文水平有限也不能直接向作者提问只能另选其他方法。

在数据库中执行存储过程无非也只是执行了一个SQL语句,专门构造了一个函数来拼接整个SQL语句,然后使用Query调用

func GetExecProcSql(procName string, inParas map[string]string, bErrorDescribe bool) string {
    var sql string

    var paras string
    for key, value := range inParas {
        paras += key + " = " + value
        paras += ","
    }

    paras = strings.TrimRight(paras, ",")
    paras += ";"

    if bErrorDescribe == true {
        sql = ""
    } else {
        sql = fmt.Sprintf("DECLARE    @return_value int; EXEC    @return_value = [dbo].[%s] %s SELECT 'Return Value' = @return_value", procName, paras)
    }

    return sql
}

 

以下是调用过程

//数据连接
    var server = "192.168.0.100"
    var port = 1433
    var user = "sa"
    var password = "123456ok!"
    var database = "THPlatformDB"

    //连接字符串
    connString := fmt.Sprintf("server=%s;port%d;database=%s;user id=%s;password=%s", server, port, database, user, password)

    //建立连接
    db, err := sql.Open("sqlserver", connString)
    if err != nil {
        log.Fatal("Open Connection failed:", err.Error())
    }
    defer db.Close()

//构造参数
    m1 := make(map[string]string)
    m1["@dwUserID"] = "1"
    m1["@nBaseEnsureType"] = "0"

    sql := GetExecProcSql("GSP_GP_LoadBaseEnsure", m1, false)

row, err := db.Query(sql)

if err != nil {
        fmt.Println(err)
    } else {
        //获取结果集
        for row.Next() {
            var GameID int
            var NickName string
            row.Scan(&GameID, &NickName)
            fmt.Println("%v,%v", GameID, NickName)
        }

        //获取返回值
        if row.NextResultSet() {
            for row.Next() {
                var returnValue int
                row.Scan(&returnValue)
                fmt.Println("测试结果 %v", returnValue)
            }
        }
    }

 

虽然整个调用略显蹩脚但是也基本能实现我想要的功能,暂时这么用以后有时间可以再研究一下

另外整个驱动有一个大坑就是对SQL Server 2008 r2支持不好,而我目前就用的这个版本的数据库,悲催,没办法只能升级数据库版本到2012解决