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

时间:2015-08-14 12:59:18

标签: sql sql-server go database-connection

我正在尝试使用带有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)
}

1 个答案:

答案 0 :(得分:10)

我想分享我使用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的小示例程序,我的搜索出现了这个问题。我想添加一些额外的信息和示例程序,以帮助其他人开始并从我的错误中吸取教训。我还发现this article GoLang and MSSQL Databases: An Example有帮助,特别是在犯了足够的错误之后我才能更好地理解它。

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

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")
}

首次对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

安装SQL Server驱动程序包

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

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

Git Shell是作为安装Git的一部分安装的github shell。我发现我必须在go get中运行Git Shell命令,以便go命令找到git应用程序并访问github存储库。当我尝试从普通命令shell运行go get命令时,我看到一条错误消息,指出找不到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

为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服务。 Using SQL Server Configuration Manager to enable 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

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

  

已知问题

     

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

所以我下载了从未实际安装过的更新。在等待下载时,我进行了更多搜索,发现包含实际SQL Server可执行文件的文件夹以及包含一系列文件LogERRORLOG等的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]

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

1> create login gouser with password='g0us3r';
2> go
1> create user gouser for login gouser;
2> go

接下来,我下载并安装了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"并且对于本地主机将是" \ userid"。我仍在研究是否能够自动使用当前登录用户的凭据。

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

但是,只有在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身份验证。

另请参阅How to make sure that you are using Kerberos authentication when you create a remote connection to an instance of SQL Server 2005,其中提供了一些其他信息以及使用setspn命令来解决问题。

另见The SQL Network Interface library was unable to register SPN

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

Windows身份验证使用Windows凭据登录到SQL Server,但未指定用户标识和密码。这称为sqlcmdODBC的可信连接;或称为go-mssqldb Go驱动程序包的单点登录。

来自go-mssqldb的github自述文件,

  

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

所以我尝试了以下两种方式使用我的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=;")

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

SQL Server Management Studio enabling SQL Authentication

enter image description here