MySQL Connector/J のユーザがよく直面する問題がいくつかあります。このセクションでは、それらの兆候と解決法を説明します。
Questions
24.4.5.3.1: MySQL Connector/J でデータベースに接続しようとすると、次の例外が出ます :
SQLException: Server configuration denies access to data source SQLState: 08001 VendorError: 0
これはなんでしょうか ?MySQL コマンドライン クライアントとは問題なく接続できます。
24.4.5.3.2: アプリケーションが SQLException 'No Suitable Driver' を投入するのですが、なぜでしょうか?
24.4.5.3.3: アプレットまたはアプリケーションで MySQL Connector/J を使用したいのですが、次に似た例外が出ます :
SQLException: Cannot connect to MySQL server on host:3306. Is there a MySQL server running on the machine/port you are trying to connect to? (java.security.AccessControlException) SQLState: 08S01 VendorError: 0
24.4.5.3.4: 1 日は問題なく動くのですが、夜の間に停止してしまうサーブレット/アプリケーションがあります。
24.4.5.3.5: JDBC-2.0 の更新可能な結果セットを使おうとすると、その結果セットは更新不可能という例外が出ます。
24.4.5.3.6: Connector/J を使って MySQL サーバに接続できません。接続パラメータが間違っているようです。
Questions and Answers
24.4.5.3.1: MySQL Connector/J でデータベースに接続しようとすると、次の例外が出ます :
SQLException: Server configuration denies access to data source SQLState: 08001 VendorError: 0
これはなんでしょうか ?MySQL コマンドライン クライアントとは問題なく接続できます。
java は Unix Domain Sockets をサポートしないため、MySQL Connector/J は MySQL への接続に TCP/IP ソケットを使用する必要があります。そのため、MySQL Connector/J が MySQL に接続する場合、MySQL サーバのセキュリティ マネージャはその grant テーブルを使用して、接続が許可されるべきかを決定します。
MySQL サーバに GRANT
文を使用して、これが起きるように、必要なセキュリティ証明書を
MySQL
サーバに追加する必要があります。詳細は
項12.5.1.3. 「GRANT 構文」 を参照。
注意.
mysql コマンドライン
クライアントでの接続のテストは、--host
フラグを加え、localhost
以外をホストに使用しなければ作動しません。mysql
コマンドライン
クライアントは、特別なホスト名
localhost
を使っている場合、Unix ドメイン
ソケットを使用しません。localhost
への接続をテストしている場合、ホスト名に
127.0.0.1
を代わりに使用してください。
注意. MySQL で権限や許可を不適切に変更すると、サーバが適したセキュリティ プロパティを持たないでインストールされる恐れがありまs。
24.4.5.3.2: アプリケーションが SQLException 'No Suitable Driver' を投入するのですが、なぜでしょうか?
このエラーには 3 つの原因が考えられます :
Connector/J driver が CLASSPATH
にない。項24.4.2. 「Connector/J のインストール」
参照。
接続 URL のフォーマットが間違っている、または誤った JDBC ドライバを参照している。
DriverManager
を使用している場合、jdbc.drivers
システム プロパティに Connector/J
ドライバのロケーションが取り込まれていない。
24.4.5.3.3: アプレットまたはアプリケーションで MySQL Connector/J を使用したいのですが、次に似た例外が出ます :
SQLException: Cannot connect to MySQL server on host:3306. Is there a MySQL server running on the machine/port you are trying to connect to? (java.security.AccessControlException) SQLState: 08S01 VendorError: 0
アプレットを起動しているか、MySQL サーバが "--skip-networking" オプション セットとインストールされている、または MySQL サーバの前にファイアウォールがあるということが考えられます。
アプレットは、そのアプレットに .class ファイルをサーブしたウェブ サーバを実行するマシンにだけネットワーク接続を確立し戻すことができます。つまり、これを実行するには、MySQL を同じマシン上で起動する必要があります ( もしくは何らかのポート リダイレクトが必要 ) 。これはまた、ローカル ファイル システムからはアプレットをテストすることができないということで、それらをいつもウェブ サーバにデプロイする必要があります。
Java は Unix ドメイン ソケットをサポートしないので、MySQL Connector/J は TCP/IP を使用して、MySQL とだけ交信することができます。MySQL を "--skip-networking" フラグで起動した場合、またはファイアウォールされている場合は、TCP/IP の MySQL との交信は影響を受けている可能性があります。
MySQL が "--skip-networking" オプション
セットと起動された場合 ( 例えば MySQL
サーバの Debian Linux
パッケージはこれを行いません ) 、file
/etc/mysql/my.cnf or /etc/my.cnf
でそれをコメントアウトする必要があります。当然、my.cnf
file もMySQL サーバの data
ディレクトリか他の場所にある場合があります
( MySQL
がシステムのためにどのようにコンパイルされたかによる
) 。MySQL AB
で作成されたバイナリは常に、/etc/my.cnf and
[datadir]/my を調査します。MySQL
サーバがファイアウォールされている場合、
MySQL が監視しているポートの MySQL サーバへ
Java コードを実行しているホストからの
TCP/IP
を許可するよう、ファイアウォールを構成する必要があります。(
デフォルトでは 3306 ) 。
24.4.5.3.4: 1 日は問題なく動くのですが、夜の間に停止してしまうサーブレット/アプリケーションがあります。
MySQL は、8 時間動きがなければ接続を閉じてしまいます。停滞した接続を扱う接続プールを使用するか、"autoReconnect" パラメータを使用する必要があります ( 項24.4.4.1. 「Connector/J の Driver/Datasource クラス名、URL シンタックス、および構成プロパティ」 参照 ) 。
また、アプリケーションが終了するまでSQLExceptions
をプロンプトするより、アプリケーションでキャッチして対処するべきでしょう。プログラミングのよい練習です。MySQL
Connector/J
は、クエリの処理中にネットワーク接続の問題に直面した場合、SQLState
( APIDOCS 内の
java.sql.SQLException.getSQLState()
参照 ) を "08S01"
に設定します。アプリケーション
コードは、この時点で MySQl
への再接続を試行します。
次の ( 単純な ) 例は、これらの例外を扱えるコードはどんな様子かを表しています。
例 24.12. リトライ ロジックとのトランザクション例
public void doBusinessOp() throws SQLException {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//
// How many times do you want to retry the transaction
// (or at least _getting_ a connection)?
//
int retryCount = 5;
boolean transactionCompleted = false;
do {
try {
conn = getConnection(); // assume getting this from a
// javax.sql.DataSource, or the
// java.sql.DriverManager
conn.setAutoCommit(false);
//
// Okay, at this point, the 'retry-ability' of the
// transaction really depends on your application logic,
// whether or not you're using autocommit (in this case
// not), and whether you're using transacational storage
// engines
//
// For this example, we'll assume that it's _not_ safe
// to retry the entire transaction, so we set retry
// count to 0 at this point
//
// If you were using exclusively transaction-safe tables,
// or your application could recover from a connection going
// bad in the middle of an operation, then you would not
// touch 'retryCount' here, and just let the loop repeat
// until retryCount == 0.
//
retryCount = 0;
stmt = conn.createStatement();
String query = "SELECT foo FROM bar ORDER BY baz";
rs = stmt.executeQuery(query);
while (rs.next()) {
}
rs.close();
rs = null;
stmt.close();
stmt = null;
conn.commit();
conn.close();
conn = null;
transactionCompleted = true;
} catch (SQLException sqlEx) {
//
// The two SQL states that are 'retry-able' are 08S01
// for a communications error, and 40001 for deadlock.
//
// Only retry if the error was due to a stale connection,
// communications problem or deadlock
//
String sqlState = sqlEx.getSQLState();
if ("08S01".equals(sqlState) || "40001".equals(sqlState)) {
retryCount--;
} else {
retryCount = 0;
}
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException sqlEx) {
// You'd probably want to log this . . .
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlEx) {
// You'd probably want to log this as well . . .
}
}
if (conn != null) {
try {
//
// If we got here, and conn is not null, the
// transaction should be rolled back, as not
// all work has been done
try {
conn.rollback();
} finally {
conn.close();
}
} catch (SQLException sqlEx) {
//
// If we got an exception here, something
// pretty serious is going on, so we better
// pass it up the stack, rather than just
// logging it. . .
throw sqlEx;
}
}
}
} while (!transactionCompleted && (retryCount > 0));
}
注意.
接続状態やデータベース状態の情報が破損する危険なしに
MySQL
サーバに再接続できる安全なメソッドはないので、autoReconnect
オプションの使用はお勧めしません。その代わり、プールからの利用可能な接続を使用して、MySQL
サーバに接続するアプリケーションを有効にする接続プールを使いましょう。autoReconnect
機能は廃止になり、今後のリリースでは除外される可能性があります。
24.4.5.3.5: JDBC-2.0 の更新可能な結果セットを使おうとすると、その結果セットは更新不可能という例外が出ます。
MySQL は行識別子を持たないため、MySQL Connector/J は、少なくともプライマリ キーをひとつ持つテーブルのクエリからの結果セットしか更新できず、クエリはすべてのプライマリ キーと、テーブルをひとつだけスパンすることができるクエリを選択する必要があります ( 結合はなし ) 。これは JDBC 仕様に概要があります。
この問題は更新可能な結果セットを使用する時にだけ起こり、Connector.J
は、各行の一意な参照なしで更新される結果セット内の正しい行を特定することができるとは保証できません。WHERE
句を使って、整合される基準値をそれぞれ特定することのできるテーブルで
UPDATE または
DELETE
文を使用している場合、テーブルに一意的なフィールドを持つのための必須条件はありません。
24.4.5.3.6: Connector/J を使って MySQL サーバに接続できません。接続パラメータが間違っているようです。
サーバで skip-networking
オプションが有効になっていないことを確かめてください。Connector/J
は TCP/IP
でサーバと通信しなければなりません。名前付きソケットはサポートされていません。また、接続を
Firewall や他のネットワーク セキュリティ
システムに通さないように注意してください。詳細は
項B.1.2.2. 「Can't connect to [local] MySQL server」
をご覧ください。
