sql >> データベース >  >> RDS >> Sqlserver

SQL Serverドライバを使用して正常に接続できず、ログインに失敗します

    SQL Server Express 2008を使用して簡単なデモGo言語データベースプログラムを作成した経験を共有したいと思います。以下の教訓は、2008以降のすべてのSQLServerバージョンに適用されると思います。

    私のSQLServerExpressは、以前はdefaultでインストールされていました namedではなくインスタンス 実例。また、Windows認証を使用するためにインストールされました。これらの設定は両方とも、私が行う他の開発作業で必要でした。私が行う他の作業では、ローカルデータベースエンジンとしてアプリケーションと同じPC上でSQLServerExpressを使用します。 GoアプリケーションでSQLServerでWindows認証を使用できることを期待していました。

    ローカルのSQLServerと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")
    }
    

    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
    

    SQLServerドライバーパッケージのインストール

    私が最初にやらなければならなかったのは、SQLServerで動作するデータベースドライバーパッケージを見つけることでした。いくつかのstackoverflowの投稿は、github.com/denisenkom/go-mssqldbを推奨しています それが使用されたものです。

    github.com/denisenkom/go-mssqldbを使用するには パッケージ最初にgo get github.com/denisenkom/go-mssqldbを使用してgithubリポジトリから取得する必要がありました Git Shellを実行して作成されたコマンドシェルウィンドウから 。

    Git Shell Gitのインストールの一部としてインストールされるgithubシェルです。 go getを実行する必要があることがわかりました Git Shellのコマンド goのために gitを検索するコマンド アプリケーションを作成し、githubリポジトリにアクセスします。 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
    

    SQLServerのTCP接続を有効にする

    いくつか検索した後、いくつかの異なるサイトを見つけました。これらはすべて、エラーが私のSQLServerインスタンスがTCP/IP用に構成されていないことを意味していることを示していました。さまざまな投稿により、Sql Server Configuration Managerを使用する必要があることが示されました TCP/IPを有効にします。

    私が発見したのは、TCP/IPを有効にする必要がある場所が実際には2つあるということです。 1つはClient Protocolsでした そしてそれは確かにすでに有効にされていました。ただし、もう1つはProtocols for MSSQLSERVERでした。 その中で、1つのTCP/IPが無効になりました。そこで、Protocols for MSSQLSERVERでTCP/IPを有効にしました。 次に、コントロールパネルの管理ツールのサービスユーティリティを使用してSQLServerサービスを再起動します。

    ただし、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リポジトリにあります:

    既知の問題

    SSL暗号化が無効になっていない場合、SQLServer2008および2008R2エンジンはログインレコードを処理できません。 SQL Server 2008 R2の問題を修正するには、SQL Server 2008 R2 Service Pack 2をインストールします。SQLServer2008の問題を修正するには、SQL Server2008SP3用のMicrosoftSQLServer 2008 ServicePack3とCumulativeupdateパッケージ3をインストールします。詳細:http://support.microsoft.com/kb/2653857

    そこで、実際にインストールしたことのないアップデートをダウンロードしました。ダウンロードを待っている間、私はさらに調べて、実際のSQLServer実行可能ファイルとLogを含むフォルダーを見つけました。 一連のファイルを含むフォルダERRORLOGERRORLOG.1 、など。

    SQLServerログはSQLServerユーザーが必要であることを示しています

    ERRORLOGを見る ファイル次のパズルのピースを提供する次のログを含むSQLServerのエラーログを見つけました:

    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認証を使用しておらず、代わりにSQLServer認証を使用していることに気付きました。空のuser id=を指定してWindows認証を使用しようとしました しかし、それはうまくいかなかったようです。したがって、sqlcmdを使用します ユーティリティ、SQLServerユーザーを作成しました。

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

    次に、Microsoft SQL ServerManagementStudioをダウンロードしてインストールしました。これは、SQLServer構成マネージャーとは異なるユーティリティです。これを使用して、2つのことを行いました。(1)SQL Server認証とWindows認証をオンにし、(2)新しいSQLServerユーザーgouserに必要なアクセス許可を提供しました。 。このユーティリティは、SQLServerとそのさまざまなデータベースを参照するための優れたユーザーインターフェイスも提供しました。

    作成するSQLユーザーに、SQLServerへの接続とデータベースの作成に使用できる十分な権限があることを確認してください。

    Windows認証を使用する際の考慮事項

    さらに調査した結果、実際にWindows認証を使用できることがわかりましたが、完全に修飾されたユーザーIDとそのパスワードを提供する必要があります。ドメイン名が「AD」のActiveDirectoryを使用している環境の場合、完全修飾ユーザーIDは「AD \ userid」になり、ローカルホストの場合は「\userid」になります。現在ログインしているユーザーの資格情報を自動的に使用できるようにすることについては、まだ調査中です。

    さらに調査し、Goドライバー開発者からの支援を見つけた後、sql.Open()があれば、現在のWindows認証が可能になるはずです。 「userid=;password=;」を意味するユーザー情報は含まれません。指定しないでください。

    ただし、現在のユーザーに対するこの形式の自動Windows認証は、SQL Serverインスタンスが有効なサービスプリンシパル名(SPN)でKerberosを使用している場合にのみ許可されます。 SQL Serverのインスタンスで再起動を実行し、ERRORLOGファイルに次のログが表示される場合、SQLServerはKerberosで初期化できませんでした。

    2016-08-23 18:32:16.77サーバーSQL Serverネットワークインターフェイスライブラリは、SQL Serverサービスのサービスプリンシパル名(SPN)を登録できませんでした。エラー:0x54b、状態:3。SPNの登録に失敗すると、統合認証がKerberosではなくNTLMにフォールバックする可能性があります。これは情報メッセージです。認証ポリシーでKerberos認証が必要な場合にのみ、追加のアクションが必要です。

    setspnを使用していくつかの追加情報を提供するSQLServer2005のインスタンスへのリモート接続を作成するときに、Kerberos認証を使用していることを確認する方法も参照してください。 問題を修正するコマンド。

    SQLネットワークインターフェイスライブラリがSPNを登録できませんでした。

    も参照してください。

    信頼できるWindows認証について (@xptによる@Richardからの要求に従って更新)

    Windows認証は、ユーザーIDとパスワードを指定せずに、Windowsクレデンシャルを使用してSQLServerにログインしています。これは、sqlcmdの信頼できる接続と呼ばれます またはODBC;または、go-mssqldbのシングルサインオンと呼ばれます ドライバーパッケージに移動します。

    go-mssqldbから githubでのreadme、

    「ユーザーID」-SQLServer認証ユーザーIDまたはWindowsAuthenticationユーザーIDをDOMAIN\User形式で入力します。 Windowsでは、ユーザーIDが空であるか欠落している場合、シングルサインオンが使用されます。

    そこで、SQL Server 2008 R2で次の2つの方法を試しましたが、どちらも正常に機能しています。

    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)を構築し、その名前はSQLServerの名前と一致する必要があります。テストで適切なサービスプリンシパル名(SPN)を使用したので、機能します。




    1. MySQLデータベースを作成する

    2. CONVERT()を使用してSQLServerで1つの日付形式から別の日付形式に変換する方法

    3. Oracleセッションで日付形式を変更する方法

    4. WindowsからMySQL5.7を完全に削除する方法