JavaからSQL Serverに接続する

MicrosoftのDBサーバ『SQL Server』に、Microsoft純正のJDBCドライバを用いてJavaから接続した際のハマりメモ。

下記のようなメッセージが表示された人向けです。

  • ERROR-CODE: 0 / SQL-STATE: 08S01

    ホスト 192.168.1.XXX、ポート 55378 への TCP/IP 接続が失敗しました。エラー: “接続のタイムアウト: 詳細情報なし。接続プロパティを調べて、SQL Server のインスタンスがホスト上で実行されていて、ポートへの TCP/IP 接続が許可されており、そのポートへの TCP 接続がファイアウォールにブロックされていないことを確認してください。”。

  • ERROR-CODE: 18456 / SQL-STATE: S0001

    ユーザーユーザ名はログインできませんでした。 ClientConnectionId:XXXXXXXXXX-XXXX-XXXXXXXXX

とりあえずの結論は、「SQL Serverの『名前付きインスタンス』と『TCP動的ポート』、ファイアウォールの設定を確認する」です。

きちんと検証はしていませんが、Accessにリンクテーブルを作ろうとした際、ODBCでも同様の現象が発生しました。
この記事に記載した内容を確認・設定しJDBC接続できるようにしたあとで、ODBC接続を試みたら難なく接続することができました。ODBC経由でSQL Serverに接続できない問題が起きているかたも、この記事の内容が役に立つと思います。


対処

  • SQL Server Browserは起動しているか?

コントロールパネルの『サービス』から確認する。
起動していない場合は、SQL Server Browserサービスを起動する。
(その他、SQL Server関連のサービスも起動されていることを確認する。これを忘れて少しハマりました。)

詳細は、Microsoftのサイトの『SQL Server Browserサービス』を参照。

  • SQL Serverが稼働しているマシンのポート開放の確認

SQL Serverへの接続に必要なポートが開放されているか、(主にSQL Serverが稼働しているリモートマシンの)ファイアウォールなどの設定を確認する。
JDBCの接続URLの記法により、必要な開放ポートが変わるので注意。

	// この部分
	Connection con = DriverManager.getConnection("jdbc:sqlserver://192.168.1.XXX:55378;instanceName=SQLEXPRESS;databaseName=データベース名", "ユーザ名", "パスワード";
“jdbc:sqlserver://192.168.1.XXX\\インスタンス名;databaseName=データベース名”の場合

ポート番号 1434とインスタンスがリッスンしているポート番号が開放されているか確認

“jdbc:sqlserver://192.168.1.XXX;instanceName=インスタンス名;databaseName=データベース名”の場合

ポート番号 1434とインスタンスがリッスンしているポート番号が開放されているか確認

“jdbc:sqlserver://192.168.1.XXX:インスタンスがリッスンしているポート番号;instanceName=インスタンス名;databaseName=データベース名”

インスタンスがリッスンしているポート番号が開放されているか確認

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で接続可能になっているかなども確認が必要です。

詳細は『構成マネージャー』を参照

2017-08-17 (2)

確認に用いたプログラム

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();
		}
	}
}

makoto について

デジタルガジェット大好き!! 小さい機械を片手に、JavaとFlex、PHPなど、いろいろなプログラミング言語・環境を行ったり来たりしながらプログラムを書いています。 最近お気に入りな環境は、Visual StudioとFileMaker。
カテゴリー: Java, Windows, コードスニペット, データベース, 技術的なメモ タグ: , , , パーマリンク