sql >> Database >  >> RDS >> Sqlserver

Go with SQL Server-stuurprogramma kan geen verbinding maken, inloggen mislukt

Ik wil mijn ervaring delen met het uitwerken van een eenvoudige demo Go-taaldatabaseprogramma met SQL Server Express 2008. Ik denk dat de volgende geleerde lessen van toepassing zijn op elke SQL Server-versie vanaf 2008 en later.

Mijn SQL Server Express was eerder geïnstalleerd met de default instantie in plaats van een named voorbeeld. Het is ook geïnstalleerd om Windows-verificatie te gebruiken. Beide instellingen waren vereist voor ander ontwikkelingswerk dat ik doe. Het andere werk dat ik doe, gebruikt SQL Server Express op dezelfde pc als de applicatie als een lokale database-engine. Ik verwachtte Windows-verificatie met SQL Server te kunnen gebruiken in mijn Go-toepassing.

Op zoek naar een stuurprogramma en een klein voorbeeldprogramma om te gebruiken met een lokale SQL Server en Go, kwam deze vraag naar voren tijdens mijn zoektocht. Ik dacht wat extra informatie en een voorbeeldprogramma toe te voegen om anderen te helpen aan de slag te gaan en van mijn fouten te leren. Ik vond ook dit artikel GoLang- en MSSQL-databases:een voorbeeld nuttig, vooral nadat ik voldoende fouten had gemaakt zodat ik het beter begreep.

De definitieve versie van mijn testprogramma is als volgt:

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

De eerste keer dat de bovenstaande toepassing wordt uitgevoerd nadat de noodzakelijke wijzigingen in de SQL Server-instellingen zijn aangebracht, wordt de volgende uitvoer gegenereerd. Aangezien de database niet bestaat de eerste keer dat het programma wordt gestart, ziet u de foutmelding afgedrukt. De volgende keren dat het wordt uitgevoerd, blijft de database bestaan ​​en wordt het foutbericht wanneer de database wordt verwijderd niet weergegeven.

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

Het SQL Server Driver-pakket installeren

Het eerste dat ik moest doen, was een databasestuurprogrammapakket vinden dat zou werken met SQL Server. Verschillende stackoverflow-posts aanbevolen github.com/denisenkom/go-mssqldb dus dat is wat het gebruikte.

Om de github.com/denisenkom/go-mssqldb te gebruiken pakket Ik moest het eerst ophalen uit de github-repository met go get github.com/denisenkom/go-mssqldb vanuit het opdrachtshell-venster gemaakt door Git Shell . uit te voeren .

Git Shell is de github-shell die wordt geïnstalleerd als onderdeel van het installeren van Git. Ik ontdekte dat ik de go get . moest uitvoeren commando in de Git Shell om de go commando om de git . te vinden applicatie en toegang tot de github-repository. Toen ik probeerde de go get . uit te voeren commando uit een normale commando-shell Ik zag een foutmelding die aangeeft dat de git opdracht kon niet worden gevonden.

Na het installeren van de go-mssqldb pakket Ik kon mijn voorbeeldtoepassing uitvoeren en liep steeds tegen een runtime-fout aan van de Open() . De output van mijn applicatie was de volgende:

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

TCP-verbindingen inschakelen voor SQL Server

Na wat zoeken vond ik een aantal verschillende sites die allemaal aangaven dat de fout betekende dat mijn SQL Server-instantie niet was geconfigureerd voor TCP/IP. De verschillende postings gaven aan dat ik de Sql Server Configuration Manager . moest gebruiken om TCP/IP in te schakelen.

Wat ik ontdekte is dat er eigenlijk twee plaatsen zijn waar TCP/IP moet worden ingeschakeld. Een daarvan was Client Protocols en dat was inderdaad al ingeschakeld. De andere was echter Protocols for MSSQLSERVER en in die ene was TCP/IP uitgeschakeld. Dus ik heb TCP/IP ingeschakeld in de Protocols for MSSQLSERVER sectie en startte vervolgens de SQL Server-service opnieuw met behulp van het servicehulpprogramma van Systeembeheer vanuit het Configuratiescherm.

Ik had echter nog steeds problemen met een vraag na het gebruik van sql.Open() . Ik zag applicatie-uitvoer die een variatie was op het volgende. De foutmelding was hetzelfde, maar wanneer functieaanroepen fouten hadden, konden deze van de ene run naar de andere veranderen. Ik heb geprobeerd de verbindingsreeks te wijzigen die is opgegeven in de sql.Open() zonder andere resultaten dan verschillende foutmeldingen.

starting app
  Error Exec db: create db -  driver: bad connection
  Error Exec db: create table -  driver: bad connection
ending app

Toen ik wat verder rondsnuffelde, vond ik deze notitie in de github-repository:

Bekende problemen

SQL Server 2008 en 2008 R2-engine kunnen aanmeldingsrecords niet verwerken als SSL-codering niet is uitgeschakeld. Om het probleem met SQL Server 2008 R2 op te lossen, installeert u SQL Server 2008 R2 Service Pack 2. Om het probleem met SQL Server 2008 op te lossen, installeert u Microsoft SQL Server 2008 Service Pack 3 en Cumulatief updatepakket 3 voor SQL Server 2008 SP3. Meer informatie:http://support.microsoft.com/kb/2653857

Dus ik heb de updates gedownload die ik eigenlijk nooit heb geïnstalleerd. Terwijl ik op de download wachtte, snuffelde ik wat rond en vond de map met het daadwerkelijke uitvoerbare bestand van SQL Server samen met het Log map met een reeks bestanden ERRORLOG , ERRORLOG.1 , enz.

SQL Server-logboeken geven aan dat SQL Server-gebruiker vereist is

Zoeken in het ERRORLOG bestand Ik vond een foutenlogboek van SQL Server met de volgende logboeken die het volgende stukje van de puzzel opleverden:

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]

Ik realiseerde me toen dat het Go SQL Server-stuurprogramma geen Windows-verificatie gebruikte, maar in plaats daarvan SQL Server-verificatie. Ik had geprobeerd Windows-verificatie te gebruiken door een lege user id= . op te geven dat bleek echter niet te werken. Dus met behulp van de sqlcmd hulpprogramma, heb ik een SQL Server-gebruiker gemaakt.

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

Vervolgens heb ik de Microsoft SQL Server Management Studio gedownload en geïnstalleerd. Dit is een ander hulpprogramma dan SQL Server Configuration Manager. Hiermee heb ik twee dingen gedaan:(1) zowel SQL Server-authenticatie als Windows-authenticatie aangezet en (2) de benodigde machtigingen voor mijn nieuwe SQL Server-gebruiker gouser gegeven . Dit hulpprogramma bood ook een mooie gebruikersinterface om door de SQL Server en zijn verschillende databases te bladeren.

Zorg ervoor dat de SQL-gebruiker die u aanmaakt voldoende machtigingen heeft zodat deze kan worden gebruikt om verbinding te maken met SQL Server en een database te maken.

Enkele overwegingen bij het gebruik van Windows-verificatie

Na verder onderzoek ontdekte ik dat ik Windows-verificatie daadwerkelijk kon gebruiken, maar het volledig gekwalificeerde gebruikers-ID en het bijbehorende wachtwoord moeten worden opgegeven. Voor een omgeving die gebruikmaakt van Active Directory met een domeinnaam van "AD" zou het volledig gekwalificeerde gebruikers-ID "AD\userid" zijn en voor de lokale host zou dit "\userid" zijn. Ik ben nog aan het onderzoeken of ik automatisch de inloggegevens van de momenteel ingelogde gebruiker kan gebruiken.

Na nog verder onderzoek en hulp van de ontwikkelaars van het Go-stuurprogramma, zou Windows-verificatie met de huidige mogelijk moeten zijn als de sql.Open() bevat niet de gebruikersinformatie die "user id=;password=;" betekent moet niet worden gespecificeerd.

Deze vorm van automatische Windows-verificatie tegen de huidige gebruiker is echter alleen toegestaan ​​als het SQL Server-exemplaar Kerberos gebruikt met een geldige Service Principal Name (SPN). Als u een herstart uitvoert op uw exemplaar van SQL Server en u ziet het volgende logboek in uw ERRORLOG-bestand, dan kon SQL Server niet initialiseren met Kerberos.

2016-08-23 18:32:16.77 Server De SQL Server Network Interface-bibliotheek kan de Service Principal Name (SPN) voor de SQL Server-service niet registreren. Fout:0x54b, status:3. Het niet registreren van een SPN kan ertoe leiden dat geïntegreerde authenticatie terugvalt op NTLM in plaats van Kerberos. Dit is een informatief bericht. Verdere actie is alleen vereist als Kerberos-authenticatie is vereist door authenticatiebeleid.

Zie ook Hoe u ervoor kunt zorgen dat u Kerberos-verificatie gebruikt wanneer u een externe verbinding maakt met een exemplaar van SQL Server 2005 dat ook wat aanvullende informatie biedt met behulp van de setspn commando om het probleem op te lossen.

Zie ook De SQL Network Interface-bibliotheek kon SPN niet registreren.

Over vertrouwde Windows-verificatie (Bijgewerkt op verzoek van @Richard door @xpt)

Windows-verificatie is inloggen op SQL Server met Windows-referenties zonder een gebruikers-ID en wachtwoord op te geven. Dit wordt een vertrouwde verbinding genoemd voor sqlcmd of ODBC; of genaamd Single-Sign-On voor go-mssqldb Go-stuurprogrammapakket.

Van go-mssqldb 's readme in github,

"gebruikers-ID" - voer de gebruikers-ID voor SQL Server-verificatie of de gebruikers-ID voor WindowsAuthentication in de indeling DOMAIN\User in. Als het gebruikers-ID leeg is of ontbreekt, wordt in Windows Single-Sign-On gebruikt.

Dus ik probeerde de volgende twee manieren met mijn SQL Server 2008 R2 en beide werken prima:

condb, errdb := sql.Open("mssql", "server=MyServer;user id=;password=DONTCARE;")
condb, errdb := sql.Open("mssql", "server=MyServer;user id=;password=;")

Houd er rekening mee dat het gebruik van server=localhost zou mislukken, omdat het belangrijk is om de juiste hostnaam te hebben, vanaf die naam bouwt het stuurprogramma de SQL Server kerberos Service Principal Name (SPN) en die naam moet overeenkomen met die van SQL Server. Ik heb een juiste Service Principal Name (SPN) gebruikt bij mijn test, dus het werkt.




  1. Hoe make_timestamp() werkt in PostgreSQL

  2. Problemen oplossen:MySQL/MariaDB-fout #1044 Е Toegang geweigerd voor gebruiker

  3. Postgresql Selecteer rijen waarbij kolom =matrix

  4. Hoe toegang krijgen tot een externe server met een lokale phpMyAdmin-client?