Tôi muốn chia sẻ kinh nghiệm của mình khi tạo ra một chương trình cơ sở dữ liệu ngôn ngữ Go demo đơn giản bằng cách sử dụng SQL Server Express 2008. Tôi tin rằng những bài học kinh nghiệm sau đây sẽ áp dụng cho bất kỳ phiên bản SQL Server nào từ năm 2008 trở lên.
SQL Server Express của tôi trước đây đã được cài đặt với default
ví dụ thay vì một named
ví dụ. Nó cũng đã được cài đặt để sử dụng Windows Authentication. Cả hai cài đặt này đều được yêu cầu bởi công việc phát triển khác mà tôi thực hiện. Công việc khác mà tôi thực hiện sử dụng SQL Server Express trên cùng một PC làm ứng dụng làm công cụ cơ sở dữ liệu cục bộ. Tôi đã mong đợi có thể sử dụng Xác thực Windows với SQL Server trong ứng dụng Go của mình.
Đang tìm kiếm một trình điều khiển và một chương trình mẫu nhỏ để sử dụng với SQL Server và Go cục bộ, câu hỏi này đã xuất hiện trong tìm kiếm của tôi. Tôi nghĩ phải thêm một chút thông tin bổ sung và một chương trình mẫu để giúp những người khác bắt đầu và học hỏi từ những sai lầm của tôi. Tôi cũng thấy bài viết này Cơ sở dữ liệu GoLang và MSSQL:Một ví dụ hữu ích, đặc biệt là sau khi mắc đủ lỗi mà tôi hiểu rõ hơn.
Phiên bản cuối cùng của chương trình thử nghiệm của tôi như sau:
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")
}
Lần đầu tiên ứng dụng trên được chạy sau khi thực hiện các thay đổi cần thiết đối với cài đặt SQL Server, nó sẽ tạo ra kết quả sau. Vì cơ sở dữ liệu không tồn tại trong lần đầu tiên chương trình được chạy, bạn sẽ thấy thông báo lỗi được in. Tuy nhiên, những lần chạy tiếp theo, cơ sở dữ liệu sẽ tồn tại và thông báo lỗi khi cơ sở dữ liệu bị loại bỏ sẽ không tồn tại.
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
Cài đặt gói trình điều khiển SQL Server
Điều đầu tiên tôi phải làm là tìm một gói trình điều khiển cơ sở dữ liệu sẽ hoạt động với SQL Server. Một số bài đăng stackoverflow được đề xuất github.com/denisenkom/go-mssqldb
vì vậy đó là những gì được sử dụng.
Để sử dụng github.com/denisenkom/go-mssqldb
gói đầu tiên tôi phải truy xuất nó từ kho lưu trữ github bằng cách sử dụng go get github.com/denisenkom/go-mssqldb
từ cửa sổ trình bao lệnh được tạo bằng cách chạy Git Shell
.
Git Shell
là github shell được cài đặt như một phần của quá trình cài đặt Git. Tôi thấy rằng tôi phải chạy go get
trong Git Shell
để go
lệnh tìm git
ứng dụng và truy cập kho lưu trữ github. Khi tôi cố gắng chạy go get
lệnh từ trình bao lệnh bình thường Tôi thấy thông báo lỗi cho biết rằng git
không thể tìm thấy lệnh.
Sau khi cài đặt go-mssqldb
gói Tôi đã có thể chạy ứng dụng mẫu của mình và tiếp tục gặp lỗi thời gian chạy từ Open()
. Kết quả từ ứng dụng của tôi như sau:
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
Bật kết nối TCP cho SQL Server
Sau một số tìm kiếm, tôi đã tìm thấy một số trang web khác nhau, tất cả đều chỉ ra rằng lỗi có nghĩa là phiên bản SQL Server của tôi không được định cấu hình cho TCP / IP. Các bài đăng khác nhau cho biết tôi cần sử dụng Sql Server Configuration Manager
để bật TCP / IP.
Những gì tôi phát hiện ra là thực sự có hai nơi mà TCP / IP cần được kích hoạt. Một là Client Protocols
và điều đó thực sự đã được kích hoạt. Tuy nhiên, cái khác là Protocols for MSSQLSERVER
và trong đó một TCP / IP đã bị vô hiệu hóa. Vì vậy, tôi đã bật TCP / IP trong Protocols for MSSQLSERVER
, sau đó khởi động lại dịch vụ SQL Server bằng tiện ích Dịch vụ của Công cụ quản trị từ Bảng điều khiển.
Tuy nhiên, tôi vẫn gặp sự cố với bất kỳ loại truy vấn nào sau khi sử dụng sql.Open()
. Tôi đã thấy đầu ra ứng dụng là một số biến thể sau đây. Thông báo lỗi giống nhau, tuy nhiên khi các lệnh gọi hàm có lỗi có thể thay đổi từ lần chạy này sang lần chạy tiếp theo. Tôi đã thử thay đổi chuỗi kết nối được chỉ định trong sql.Open()
không có kết quả nào ngoài các thông báo lỗi khác nhau.
starting app
Error Exec db: create db - driver: bad connection
Error Exec db: create table - driver: bad connection
ending app
Tìm hiểu kỹ hơn, tôi tìm thấy ghi chú này trong kho lưu trữ github:
Các vấn đề đã biết
Công cụ SQL Server 2008 và 2008 R2 không thể xử lý các bản ghi đăng nhập khi mã hóa SSL không bị tắt. Để khắc phục sự cố SQL Server 2008 R2, hãy cài đặt SQL Server 2008 R2 Gói Dịch vụ 2. Để khắc phục sự cố SQL Server 2008issue, hãy cài đặt Microsoft SQL Server 2008 Gói Dịch vụ 3 và Gói tích luỹ 3 cho SQL Server 2008 SP3. Thông tin thêm:http://support.microsoft.com/kb/2653857
Vì vậy, tôi đã tải xuống các bản cập nhật mà tôi chưa bao giờ thực sự cài đặt. Trong khi chờ tải xuống, tôi đã tìm kiếm xung quanh nhiều hơn và tìm thấy thư mục chứa tệp thực thi SQL Server thực cùng với Log
thư mục chứa một loạt tệp ERRORLOG
, ERRORLOG.1
, v.v.
Nhật ký SQL Server cho biết yêu cầu người dùng SQL Server
Tìm kiếm trong ERRORLOG
tệp Tôi đã tìm thấy nhật ký lỗi của SQL Server với các nhật ký sau cung cấp phần tiếp theo của câu đố:
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]
Sau đó, tôi nhận ra rằng trình điều khiển Go SQL Server không sử dụng Xác thực Windows mà thay vào đó đang sử dụng Xác thực SQL Server. Tôi đã cố gắng sử dụng Xác thực Windows bằng cách chỉ định một user id=
trống tuy nhiên điều đó dường như không hoạt động. Vì vậy, sử dụng sqlcmd
tiện ích, tôi đã tạo một người dùng SQL Server.
1> create login gouser with password='g0us3r';
2> go
1> create user gouser for login gouser;
2> go
Tiếp theo, tôi đã tải xuống và cài đặt Microsoft SQL Server Management Studio. Đây là một tiện ích khác với Trình quản lý cấu hình SQL Server. Bằng cách sử dụng này, tôi đã thực hiện hai việc:(1) bật Xác thực máy chủ SQL cũng như Xác thực Windows và (2) cung cấp các quyền cần thiết cho người dùng SQL Server mới của tôi gouser
. Tiện ích này cũng cung cấp một giao diện người dùng đẹp để duyệt qua SQL Server và các cơ sở dữ liệu khác nhau của nó.
Đảm bảo rằng người dùng SQL mà bạn tạo có đủ quyền để có thể sử dụng nó để kết nối với SQL Server và tạo cơ sở dữ liệu.
Một số cân nhắc khi sử dụng xác thực Windows
Sau khi nghiên cứu thêm, tôi thấy rằng tôi thực sự có thể sử dụng Xác thực Windows tuy nhiên phải cung cấp id người dùng hoàn toàn đủ điều kiện và mật khẩu của nó. Đối với môi trường sử dụng Active Directory với tên miền "AD", id người dùng đủ điều kiện sẽ là "AD \ userid" và đối với máy chủ cục bộ sẽ là "\ userid". Tôi vẫn đang nghiên cứu về việc có thể tự động sử dụng thông tin đăng nhập của người dùng hiện đang đăng nhập.
Sau khi vẫn nghiên cứu thêm và tìm sự hỗ trợ từ các nhà phát triển trình điều khiển Go, Xác thực Windows với hiện tại sẽ có thể thực hiện được nếu sql.Open()
không bao gồm thông tin người dùng có nghĩa là "id người dùng =; mật khẩu =;" không nên được chỉ định.
Tuy nhiên, hình thức Xác thực Windows tự động này đối với người dùng hiện tại chỉ được phép nếu phiên bản SQL Server đang sử dụng Kerberos với Tên chính của Dịch vụ (SPN) hợp lệ. Nếu bạn thực hiện khởi động lại phiên bản SQL Server của mình và bạn thấy nhật ký sau trong tệp ERRORLOG của mình, thì SQL Server không thể khởi chạy bằng Kerberos.
2016-08-23 18:32:16.77 Máy chủ Thư viện Giao diện Mạng Máy chủ SQL không thể đăng ký Tên chính của Dịch vụ (SPN) cho Dịch vụ Máy chủ SQL. Lỗi:0x54b, trạng thái:3. Việc không đăng ký SPN có thể khiến xác thực tích hợp trở lại NTLM thay vì Kerberos. Đây là một thông báo cung cấp thông tin. Chỉ cần thực hiện thêm hành động nếu xác thực Kerberos được yêu cầu bởi chính sách xác thực.
Xem thêm Cách đảm bảo rằng bạn đang sử dụng xác thực Kerberos khi tạo kết nối từ xa đến một phiên bản của SQL Server 2005 cung cấp một số thông tin bổ sung cũng như sử dụng setspn
lệnh để khắc phục sự cố.
Xem thêm Thư viện giao diện mạng SQL không thể đăng ký SPN.
Giới thiệu về Xác thực Windows đáng tin cậy (Cập nhật theo yêu cầu từ @Richard bởi @xpt)
Xác thực Windows đang đăng nhập vào SQL Server bằng thông tin đăng nhập Windows mà không chỉ định id người dùng và mật khẩu. Đây được gọi là kết nối đáng tin cậy cho sqlcmd
hoặc ODBC
; hoặc được gọi là Đăng nhập một lần cho go-mssqldb
Gói trình điều khiển đi.
Từ go-mssqldb
readme của github,
"id người dùng" - nhập id người dùng Xác thực Máy chủ SQL hoặc id người dùng Xác thực Windows ở định dạng DOMAIN \ Người dùng. Trên Windows, nếu userid trống hoặc bị thiếu Đăng nhập một lần được sử dụng.
Vì vậy, tôi đã thử hai cách sau với SQL Server 2008 R2 của mình và cả hai đều hoạt động tốt:
condb, errdb := sql.Open("mssql", "server=MyServer;user id=;password=DONTCARE;")
condb, errdb := sql.Open("mssql", "server=MyServer;user id=;password=;")
Lưu ý rằng việc sử dụng server =localhost sẽ không thành công, vì điều quan trọng là phải có tên máy chủ lưu trữ chính xác, từ tên đó, trình điều khiển đang xây dựng Tên chính của dịch vụ kerberos SQL Server (SPN) và tên đó phải khớp với SQL Server. Tôi đã sử dụng Tên chính của dịch vụ (SPN) phù hợp với thử nghiệm của mình để nó hoạt động.