MicrosoftのDBサーバ『SQL Server』に、Microsoft純正のJDBCドライバを用いてJavaから接続した際のハマりメモ。
下記のようなメッセージが表示された人向けです。
ホスト 192.168.1.XXX、ポート 55378 への TCP/IP 接続が失敗しました。エラー: “接続のタイムアウト: 詳細情報なし。接続プロパティを調べて、SQL Server のインスタンスがホスト上で実行されていて、ポートへの TCP/IP 接続が許可されており、そのポートへの TCP 接続がファイアウォールにブロックされていないことを確認してください。”。
ユーザー ‘ユーザ名‘ はログインできませんでした。 ClientConnectionId:XXXXXXXXXX-XXXX-XXXXXXXXX
とりあえずの結論は、「SQL Serverの『名前付きインスタンス』と『TCP動的ポート』、ファイアウォールの設定を確認する」です。
きちんと検証はしていませんが、Accessにリンクテーブルを作ろうとした際、ODBCでも同様の現象が発生しました。
この記事に記載した内容を確認・設定しJDBC接続できるようにしたあとで、ODBC接続を試みたら難なく接続することができました。ODBC経由でSQL Serverに接続できない問題が起きているかたも、この記事の内容が役に立つと思います。
コントロールパネルの『サービス』から確認する。
起動していない場合は、SQL Server Browserサービスを起動する。
(その他、SQL Server関連のサービスも起動されていることを確認する。これを忘れて少しハマりました。)
詳細は、Microsoftのサイトの『SQL Server Browserサービス』を参照。
SQL Serverへの接続に必要なポートが開放されているか、(主にSQL Serverが稼働しているリモートマシンの)ファイアウォールなどの設定を確認する。
JDBCの接続URLの記法により、必要な開放ポートが変わるので注意。
// この部分 Connection con = DriverManager.getConnection("jdbc:sqlserver://192.168.1.XXX:55378;instanceName=SQLEXPRESS;databaseName=データベース名", "ユーザ名", "パスワード";
ポート番号 1434とインスタンスがリッスンしているポート番号が開放されているか確認
ポート番号 1434とインスタンスがリッスンしているポート番号が開放されているか確認
インスタンスがリッスンしているポート番号が開放されているか確認
URL記法の詳細は『接続URLの構築』、開放ポートの詳細は『インターネットを介しての SQL Server への接続』を参照
URLの中にユーザ名やパスワードを持たせた場合、java.sql.DriverManager#getConnection(String url)も使える。
PostgreSQLなどをJDBCを介して使っていると、つい接続URLに”jdbc:sqlserver://192.168.1.XXX:インスタンスがリッスンしているポート番号\\インスタンス名;databaseName=データベース名”みたいな書き方をしてしまいますが、これが受け付けてもらえず例外が発生しLocalizedMessageプロパティには「ポート番号 1433\SQLEXPRESS は無効です。」というようなメッセージが設定されます。(ErrorCodeプロパティには0、SqlStateプロパティにはnullが設定されていました)
SQL Server構成マネージャーを起動し、『SQL Serverネットワークの構成』からSQL Serverのインスタンスを選択し、一覧表示されたプロトコルから『TCP/IP』を選択。
プロパティを表示し、『IP All』の『TCP動的ポート』に設定されている値を確認する。
SQL Server構成マネージャーは、スタートメニューの検索ボックスで「sqlservermanager12.msc」とか「sqlservermanager13.msc」とか打ち込むと表示される。
されない場合は、\Windows\SysWOW64のフォルダあたりを探す。
そもそもSQL Serverがリモート接続可能な状態で動いているか、TCP/IPで接続可能になっているかなども確認が必要です。
詳細は『構成マネージャー』を参照
Windows 10上で稼働しているSQL Server 2014 Expressに、リモートのMacから接続して検証。
Mac側のJava環境はJava SE 7(1.7.0_51)、JDBCドライバは『Microsoft JDBC Driver 6.0 for SQL Server』のJDBC 4.1版を使用。
// This software is distributed under the license of NYSL. // ( http://www.kmonos.net/nysl/ ) import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import com.microsoft.sqlserver.jdbc.SQLServerException; public class Test { public static void main(String[] args) { // 名前付きインスタンス"SQLEXPRESS"上のデータベースに接続する際のJDBCの接続URL // ポート1434とTCP動的ポートの開放が必要 String url = "jdbc:sqlserver://192.168.1.XXX\\SQLEXPRESS;databaseName=データベース名"; // ポート1434とTCP動的ポートの開放が必要 // String url = "jdbc:sqlserver://192.168.1.XXX;instanceName=SQLEXPRESS;databaseName=データベース名"; // TCP動的ポートの開放が必要 // String url = "jdbc:sqlserver://192.168.1.XXX:55378;instanceName=SQLEXPRESS;databaseName=データベース名"; // SQL Serverのユーザ名とパスワード String username = "ユーザ名"; String password = "パスワード"; try { // JDBCドライバをロード Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); // SQL Serverに接続 Connection con = DriverManager.getConnection(url, username, password); // SQL Serverに問い合わせ Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("select * from 適当なテーブル"); while (rs.next()) { System.out.println(rs.getString("テーブルの適当な項目")); } // 後処理 rs.close(); stmt.close(); con.close(); } catch (SQLServerException e) { // SQL Server固有の例外 System.out.println("ERROR-CODE:\t" + e.getErrorCode()); System.out.println("SQL-STATE:\t" + e.getSQLState()); System.out.println("MESSAGE:\t" + e.getLocalizedMessage()); e.printStackTrace(); } catch (Exception e) { // その他の例外 e.printStackTrace(); } } }