使用SQL Server驱动程序无法成功连接,登录失败

rah*_*ele 5 sql sql-server database-connection go

我试图使用带有Go程序的Microsoft SQL Server连接到SQL Server中的数据库并从数据库中读取一些数据.

但是,当我使用err=db.ping()它时会导致错误,该错误表示:

用户'sakhaloo'登录失败

我从这个目录下载了驱动程序包的zip文件:github.com/denisenkom/go-mssqldb然后我复制压缩文件中的文件并将它们粘贴到以下地址:C:\Go\src\github.com\denisenkom\go-mssqldb

另一个问题是,当我尝试使用SQL Server 2014 Management Studio打开我的SQL数据库时,它不接受我的用户名或密码,实际上当我输入用户名和密码时会导致此错误:

已成功与服务器建立连接,但在登录过程中发生错误.(提供程序:共享内存提供程序,错误:0 - 管道的另一端没有进程.)(Microsoft SQL Server,错误:233)

我不知道这个过程有什么问题.

这是我的代码:

package main
import (
   //_ "code.google.com/p/odbc"
    _ "github.com/denisenkom/go-mssqldb"
    "database/sql"
    "fmt"
    "log"
    //"github.com/astaxie/beedb"
   // "github.com/weigj/go-odbc"
)

var (
    uName, pass string
    p *Person
)

type Person struct {
    userName string
    passWord string
    Email string
}

func main() {
    db, err := sql.Open("mssql", "server=SAKHALOO-PC;user id=sakhaloo;password=hoollehayerazi;database=webApp" )
    if err != nil {
        log.Fatal(err) 
    }
    defer db.Close()
    err = db.Ping()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Please enter your full name & password:")
    fmt.Scanln(&uName, &pass)
    row := db.QueryRow("SELECT username, password, email FROM user WHERE username=? and password=?", uName, pass)
    fmt.Println(row)
    p := new(Person)
    err = row.Scan(&p.userName, &p.passWord, &p.Email)
    fmt.Printf("%s , %s , %s \n", p.userName, p.passWord, p.Email)
    fmt.Printf("Hi %s, your email address is : %s", uName, p.Email)
}
Run Code Online (Sandbox Code Playgroud)

Ric*_*ers 11

我想分享我使用SQL Server Express 2008编写一个简单的演示Go语言数据库程序的经验.我相信以下经验教训将适用于2008年及以后的任何SQL Server版本.

我的SQL Server Express以前是与default实例一起安装的,而不是named实例.它还安装使用Windows身份验证.我做的其他开发工作都需要这两个设置.我做的其他工作在同一台PC上使用SQL Server Express作为本地数据库引擎.我希望能够在Go应用程序中使用Windows身份验证和SQL Server.

寻找一个驱动程序和一个小示例程序与本地SQL Server和Go一起使用,我的搜索出现了这个问题.我想添加一些额外的信息和示例程序,以帮助其他人开始并从我的错误中吸取教训.我还发现这篇文章GoLang和MSSQL数据库:一个例子有用,特别是在我犯了足够的错误之后我更了解它.

我的测试程序的最终版本如下:

package main

import (
    "fmt"
    "log"
    "database/sql"
     _ "github.com/denisenkom/go-mssqldb"     // the underscore indicates the package is used
)    

func main() {
    fmt.Println("starting app")

    // the user needs to be setup in SQL Server as an SQL Server user.
    // see create login and the create user SQL commands as well as the
    // SQL Server Management Studio documentation to turn on Hybrid Authentication
    // which allows both Windows Authentication and SQL Server Authentication.
    // also need to grant to the user the proper access permissions.
    // also need to enable TCP protocol in SQL Server Configuration Manager.
    //
    // you could also use Windows Authentication if you specify the fully qualified
    // user id which would specify the domain as well as the user id.
    // for instance you could specify "user id=domain\\user;password=userpw;".

    condb, errdb := sql.Open("mssql", "server=localhost;user id=gouser;password=g0us3r;")
    if errdb  != nil {
        fmt.Println("  Error open db:", errdb.Error())
    }

    defer condb.Close()

    errdb = condb.Ping()
    if errdb != nil {
        log.Fatal(errdb)
    }

    // drop the database if it is there so we can recreate it
    // next we will recreate the database, put a table into it,
    // and add a few rows.
    _, errdb = condb.Exec("drop database mydbthing")
    if errdb != nil {
        fmt.Println("  Error Exec db: drop db - ", errdb.Error())
    }

    _, errdb = condb.Exec("create database mydbthing")
    if errdb  != nil {
        fmt.Println("  Error Exec db: create db - ", errdb.Error())
    }

    _, errdb = condb.Exec("use  mydbthing")
    if errdb  != nil {
        fmt.Println("  Error Exec db: using db - ", errdb.Error())
    }

    _, errdb = condb.Exec("create table junky (one int, two int)")
    if errdb  != nil {
        fmt.Println("  Error Exec db: create table - ", errdb.Error())
    }

    _, errdb = condb.Exec("insert into junky (one, two) values (101, 201)")
    if errdb  != nil {
        fmt.Println("  Error Exec db: insert table 1 - ", errdb.Error())
    }
    _, errdb = condb.Exec("insert into junky (one, two) values (102, 202)")
    if errdb  != nil {
        fmt.Println("  Error Exec db: insert table 2 - ", errdb.Error())
    }
    _, errdb = condb.Exec("insert into junky (one, two) values (103, 203)")
    if errdb  != nil {
        fmt.Println("  Error Exec db: insert table 3 - ", errdb.Error())
    }

    // Now that we have our database lets read some records and print them.
    var (
        one  int
        two  int
    )

    // documentation about a simple query and results loop is at URL
    // http://go-database-sql.org/retrieving.html
    // we use Query() and not Exec() as we expect zero or more rows to
    // be returned. only use Query() if rows may be returned.
    fmt.Println ("  Query our table for the three rows we inserted.")
    rows, errdb := condb.Query ("select one, two from junky")
    defer rows.Close()
    for rows.Next() {
        err:= rows.Scan (&one, &two)
        if err != nil {
            fmt.Println("  Error Query db: select - ", err.Error())
        } else {
            fmt.Printf("    - one %d and two %d\n", one, two)
        }
    }
    rows.Close()

    errdb = rows.Err()
    if errdb != nil {
        fmt.Println("  Error Query db: processing rows - ", errdb.Error())
    }

    fmt.Println("ending app")
}
Run Code Online (Sandbox Code Playgroud)

一旦对SQL Server设置进行必要的更改,第一次运行上述应用程序,它将生成以下输出.由于第一次运行程序时数据库不存在,您将看到打印的错误消息.但是随后运行时数据库将存在,并且不会输出数据库丢弃时的错误消息.

starting app
  Error Exec db: drop db -  mssql: Cannot drop the database 'mydbthing', because it does not exist or you do not have permission.
  Query our table for the three rows we inserted.
    - one 101 and two 201
    - one 102 and two 202
    - one 103 and two 203
ending app
Run Code Online (Sandbox Code Playgroud)

安装SQL Server驱动程序包

我要做的第一件事是找到一个可以与SQL Server一起使用的数据库驱动程序包.建议github.com/denisenkom/go-mssqldb使用几个stackoverflow发布的内容.

为了使用该github.com/denisenkom/go-mssqldb包,我必须首先使用go get github.com/denisenkom/go-mssqldb运行创建的命令shell窗口从github存储库中检索它Git Shell.

Git Shell是作为安装Git的一部分安装的github shell.我发现,我已经运行go get的命令Git Shell,以使go命令来查找git应用程序和访问GitHub的仓库.当我尝试go get从正常的命令shell 运行该命令时,我看到一条错误消息,指示git无法找到该命令.

安装go-mssqldb包之后,我能够运行我的示例应用程序并继续运行来自的运行时错误Open().我的应用程序的输出如下:

starting app

Error Exec db: create db -  Unable to open tcp connection with host 'localhost:1433': dial tcp 127.0.0.1:1433: connectex: No connection could be made because the target machine actively refused it.

ending app
Run Code Online (Sandbox Code Playgroud)

为SQL Server启用TCP连接

经过一些搜索,我发现了许多不同的网站,这些网站都表明错误意味着我的SQL Server实例没有配置为TCP/IP.各种帖子表明我需要使用它Sql Server Configuration Manager来启用TCP/IP.

我发现实际上有两个地方需要启用TCP/IP.一个是Client Protocols,而且确实已经启用了.然而另一个是,Protocols for MSSQLSERVER并且在那个TCP/IP被禁用.因此,我在该Protocols for MSSQLSERVER部分中启用了TCP/IP ,然后使用"控制面板"中"管理工具"的"服务"实用程序重新启动了SQL Server服务. 使用SQL Server配置管理器启用TCP

但是在使用后我仍然遇到任何类型的查询问题sql.Open().我看到应用程序输出是以下的一些变化.错误消息是相同的,但是当函数调用有错误时可能会从一次运行更改为下一次运行.我尝试更改sql.Open()除了不同的错误消息之外没有结果的指定的连接字符串.

starting app
  Error Exec db: create db -  driver: bad connection
  Error Exec db: create table -  driver: bad connection
ending app
Run Code Online (Sandbox Code Playgroud)

进一步探索我在github存储库中找到了这个注释:

已知的问题

未禁用SSL加密时,SQL Server 2008和2008 R2引擎无法处理登录记录.若要解决SQL Server 2008 R2问题,请安装SQL Server 2008 R2 Service Pack 2.要修复SQL Server 2008问题,请为SQL Server 2008 SP3安装Microsoft SQL Server 2008 Service Pack 3和累积更新包3.更多信息:http: //support.microsoft.com/kb/2653857

所以我下载了我从未实际安装过的更新.而在下载等待,我戳各地越来越发现包含实际的SQL Server可执行与沿文件夹Log包含一系列文件夹ERRORLOG,ERRORLOG.1等等.

SQL Server日志表明需要SQL Server用户

ERRORLOG文件中查找我发现SQL Server的错误日志,其中包含以下日志,这些日志提供了下一个难题:

2016-08-15 22:56:22.41 Server      SQL Server is now ready for client connections. This is an informational message; no user action is required.
2016-08-15 23:55:47.51 Logon       Error: 18456, Severity: 14, State: 58.
2016-08-15 23:55:47.51 Logon       Login failed for user 'rchamber'. Reason: An attempt to login using SQL authentication failed. Server is configured for Windows authentication only. [CLIENT: 127.0.0.1]
2016-08-15 23:55:47.61 Logon       Error: 18456, Severity: 14, State: 58.
2016-08-15 23:55:47.61 Logon       Login failed for user 'rchamber'. Reason: An attempt to login using SQL authentication failed. Server is configured for Windows authentication only. [CLIENT: ::1]
2016-08-15 23:55:47.62 Logon       Error: 18456, Severity: 14, State: 58.
2016-08-15 23:55:47.62 Logon       Login failed for user 'rchamber'. Reason: An attempt to login using SQL authentication failed. Server is configured for Windows authentication only. [CLIENT: 127.0.0.1]
Run Code Online (Sandbox Code Playgroud)

然后我意识到Go SQL Server驱动程序没有使用Windows身份验证,而是使用SQL Server身份验证.我试图通过指定一个空来尝试使用Windows身份验证,user id=但这似乎不起作用.因此,使用该sqlcmd实用程序,我创建了一个SQL Server用户.

1> create login gouser with password='g0us3r';
2> go
1> create user gouser for login gouser;
2> go
Run Code Online (Sandbox Code Playgroud)

接下来,我下载并安装了Microsoft SQL Server Management Studio.这是与SQL Server配置管理器不同的实用程序.使用这个我做了两件事:(1)打开SQL Server身份验证以及Windows身份验证,(2)为我的新SQL Server用户提供必要的权限gouser.该实用程序还提供了一个很好的用户界面来浏览SQL Server及其各种数据库.

确保您创建的SQL用户具有足够的权限,以便可以使用它来连接到SQL Server并创建数据库.

使用Windows身份验证的一些注意事项

经过进一步研究后,我发现我实际上可以使用Windows身份验证,但必须提供完全限定的用户ID和密码.对于使用域名为"AD"的Active Directory的环境,完全限定的用户ID为"AD\userid",本地主机的用户ID为"\ userid".我仍然在研究能够自动使用当前登录用户的凭据.

在进一步研究并从Go驱动程序开发人员那里寻求帮助之后,如果sql.Open()不包含意味着"user id =; password =;"的用户信息,则应该可以使用当前的Windows身份验证.不应该指定.

但是,只有在SQL Server实例使用具有有效服务主体名称(SPN)的Kerberos时,才允许针对当前用户进行这种形式的自动Windows身份验证.如果在SQL Server实例上执行重新启动,并且在ERRORLOG文件中看到以下日志,则SQL Server无法使用Kerberos进行初始化.

2016-08-23 18:32:16.77服务器SQL Server网络接口库无法注册SQL Server服务的服务主体名称(SPN).错误:0x54b,状态:3.无法注册SPN可能导致集成身份验证回退到NTLM而不是Kerberos.这是一条情报信息.只有在身份验证策略需要Kerberos身份验证时,才需要采取进一步操作.

另请参阅如何在创建与SQL Server 2005实例的远程连接时确保使用Kerberos身份验证,该实例还提供了一些其他信息以及使用该setspn命令来更正问题.

另请参见SQL网络接口库无法注册SPN.

关于受信任的Windows身份验证(根据@xdhard的请求更新@xpt)

Windows身份验证使用Windows凭据登录到SQL Server,而不指定用户标识和密码.这称为sqlcmd或的可信连接ODBC; 或者称为go-mssqldbGo - driver包的Single-Sign-On .

来自go-mssqldbgithub的自述文件,

"user id" - 以DOMAIN\User格式输入SQL Server身份验证用户ID或Windows身份验证用户ID.在Windows上,如果用户标识为空或缺少使用单点登录.

所以我尝试了以下两种方式使用我的SQL Server 2008 R2,两者都运行良好:

condb, errdb := sql.Open("mssql", "server=MyServer;user id=;password=DONTCARE;")
condb, errdb := sql.Open("mssql", "server=MyServer;user id=;password=;")
Run Code Online (Sandbox Code Playgroud)

请注意,使用server = localhost会失败,因为拥有正确的主机名很重要,从该名称驱动程序正在构建SQL Server kerberos服务主体名称(SPN),并且该名称必须与SQL Server匹配.我在测试中使用了正确的服务主体名称(SPN),因此它可以工作.

SQL Server Management Studio启用SQL身份验证

在此输入图像描述