我正在尝试使用带有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)
}
答案 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服务。
但是在使用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可执行文件的文件夹以及包含一系列文件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]
然后我意识到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,但未指定用户标识和密码。这称为sqlcmd
或ODBC
的可信连接;或称为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),因此它可以工作。