JDBC を使用して MySQL を操作するための簡単な分析では、Class.forName("com.mysql.jdbc.Driver") を追加する必要があります。

JDBC を使用して MySQL を操作するための簡単な分析では、Class.forName("com.mysql.jdbc.Driver") を追加する必要があります。

導入

データベースに接続するためにJDBCを使用することに慣れている場合は、データベースに接続するためのコードはClass.forNameに基づいている必要があることを知っている必要があります。

("com.mysql.jdbc.Driver");
  パブリック静的Connection getConnection() はClassNotFoundException、SQLExceptionをスローします {
    if (接続 == null) {
      クラス.forName("com.mysql.jdbc.Driver");
      接続 = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxxxx");
    }
    接続を返します。
  }

これまで、なぜこのようなステートメントが必要なのか考えたことはありませんでした。ドキュメントに従って実行するだけです。この記事では、そうする理由を説明してみたいと思います。

クラスローディングメカニズム

その前に、Java のクラスロードメカニズムについて説明しましょう。

Java では、クラスを使用する場合は、そのクラスが JVM にロードされている必要があります。ロード プロセスは、実際には、クラスの完全修飾名を通じてクラスを定義するバイナリ バイト ストリームを取得し、バイト ストリームによって表される静的ストレージ構造をメソッドの動的ランタイム データ構造に変換することです。同時に、メソッド領域内のこのクラスのデータ アクセス エントリとして、java.lang.Class オブジェクトがメモリ内にインスタンス化されます (ここでの使用のため)。

次のような状況では、クラスのロードがトリガーされる可能性があります (<<Java 仮想マシンの詳細な理解>> から引用)。

1. 4 つのバイトコード命令 new、getstatic、putstatic、または invokestatic に遭遇したときに、クラスが初期化されていない場合は、まずその初期化をトリガーする必要があります。これら 4 つの命令を生成する最も一般的な Java コード シナリオは、new キーワードを使用してオブジェクトをインスタンス化する場合、クラスの静的フィールドを読み取ったり設定する場合 (final によって変更され、コンパイル時に結果が定数プールに配置される静的フィールドを除く)、およびクラスの静的メソッドを呼び出す場合です。

2. java.lang.reflect パッケージのメソッドを使用してクラスをリフレクションで呼び出す場合、クラスが初期化されていない場合は、まずその初期化をトリガーする必要があります。

3. クラスを初期化するときに、その親クラスが初期化されていないことが判明した場合は、まずその親クラスの初期化をトリガーする必要があります。

4. 仮想マシンが起動すると、ユーザーは実行するメイン クラス (main() メソッドを含むクラス) を指定する必要があり、仮想マシンは最初にこのメイン クラスを初期化します。

クラス.forName

公式 Java ドキュメントでは、Class.forName は実行時にクラスを動的にロードし、戻り値は生成された Class オブジェクトであると説明されています。

そうすると、jdbc でClass.forName("com.mysql.jdbc.Driver");を使用すると、com.mysql.jdbc.Driver クラスが JVM にロードされるだけであることは明らかであり、ほとんどの人はこの理由を知っているはずです。

しかし、Class.forName はクラスをロードするだけであり、返された Class オブジェクトに対して何の操作も行わないことを知っておく必要があります。では、なぜ後でそれを直接使用できるのでしょうか。

まず、Class.forName はネイティブ メソッド forName0(...); を呼び出します。

@発信者センシティブ
パブリック スタティック クラス <?> forName(String className)
      ClassNotFoundException をスローします {
  クラス<?> 呼び出し元 = Reflection.getCallerClass();
  forName0(className, true, ClassLoader.getClassLoader(caller), caller) を返します。
}

プライベート静的ネイティブ Class<?> forName0(String name、boolean initialize、ClassLoader loader、Class<?> caller);

forName0 には、クラスのロード後に初期化を実行するかどうかを示すために使用される boolean initialize というキー パラメーターがあることに注意してください。コード内で true の場合、初期化操作が実行されることを意味することがわかります。

初期化プロセスは、実際には変数に値を割り当てるプロセスです(初期値を割り当てたり、コンストラクターを呼び出したりすることはありません)。親クラスの初期化を含む、すべてのクラス変数の割り当てと静的コード ステートメント ブロックの実行コードが含まれます。

com.mysql.jdbc.Driver ドライバー クラスを確認します。

パブリッククラスDriverはNonRegisteringDriverを拡張し、java.sql.Driverを実装します。
  パブリックDriver()はSQLExceptionをスローします{
  }

  静的{
    試す {
      DriverManager.registerDriver(新しいDriver());
    } キャッチ (SQLException var1) {
      throw new RuntimeException("ドライバーを登録できません!");
    }
  }
}

このクラスには静的コード ブロックが定義されています。静的コード ブロック内にドライバー クラスのインスタンスが作成され、DriverManager に登録されます。静的コード ブロックの内容は初期化プロセス中に実行されるため、 DriverManager.getConnectionを通じて直接接続を取得できます。

その他のロードクラスメソッド

理解しておく必要があるのは、Java では、クラスを明示的にロードできるのは Class.forName() だけではないということです。では、Class.forName() の代わりに他の読み込みメソッドを使用しないのはなぜでしょうか?

ClassLoader.getSystemClassLoader().loadClass()

クラスは、クラス ローダーを介して JVM にロードすることもできます。ドライバー クラスはClassLoader.getSystemClassLoader().loadClass("com.mysql.jdbc.Driver");

しかし、loadClass の実装を詳しく見てみると、

パブリック Class<?> loadClass(String name) は ClassNotFoundException をスローします {
  loadClass(name, false) を返します。
}

保護された Class<?> loadClass(String name, boolean resolve);

オーバーロードされたメソッドが呼び出され、そのメソッドにもブール変数 boolean resolve があり、呼び出されるとデフォルトで false に設定されることがわかります。このパラメータは、ロードされたクラスをリンクするかどうかを識別するために使用されます。リンクしない場合は、初期化操作は行われません。

したがって、このクラスロード方法を使用すると、理論的にはドライバークラスは使用できません。

新しいキーワード

また、new キーワードを使用して読み込み操作を実行することもできます。new キーワードを使用すると、クラスが読み込まれているかどうかがチェックされます。読み込まれていない場合は、クラスが読み込まれます。したがって、クラスでは次のように記述することもできます。

パブリック静的Connection getConnection() はClassNotFoundException、SQLExceptionをスローします {
  if (接続 == null) {
    new Driver(); //静的コード ブロックは自動的に呼び出されます connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxx");
  }
  接続を返します。
}

しかし実際には、ドライバー クラスの静的コード ブロック内に、オブジェクトをインスタンス化して DriverMananger に登録する操作がすでに存在します。したがって、ここではオブジェクトをインスタンス化するプロセスはまったくありません。最適化プロセスとみなせる Class.forName を使用するだけです。

Class.forName("com.mysql.jdbc.Driver")を使用する必要はありません。

テスト中に、 Class.forName("com.mysql.jdbc.Driver")明示的に使用しなくてもデータベースに接続できることがわかり、非常に奇妙だと感じました。

コードを詳細に追跡した結果、MySQL ドライバー パッケージを導入すると、使用時にドライバー パッケージで提供される構成ファイルに従って、デフォルトでクラスが作成されることがわかりました。

したがって、実際には、ドライバー パッケージが導入されている限り、jdbc を使用して DriverManage を介して直接接続を取得できます。

パブリック静的接続getConnection() SQLException {
  DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx?serverTimezone=UTC", "root", "xxxxxx"); を返します。
}

要約する

上記は、JDBC を使用して MySQL を操作するときに Class.forName("com.mysql.jdbc.Driver") を追加する必要がある理由についての紹介です。お役に立てれば幸いです。ご質問がある場合は、メッセージを残してください。すぐに返信いたします。また、123WORDPRESS.COM ウェブサイトをサポートしてくださっている皆様にも感謝申し上げます。

以下もご興味があるかもしれません:
  • データベース接続のURLの詳細な説明と概要
  • MySql リンク URL パラメータの設定について
  • MySQLのdriverClassNameとurlの使い方

<<:  Vueフロントエンドの効率的な開発のためのレンダリング手順をリストします

>>:  Windows に Docker をインストールする詳細なチュートリアル

推薦する

Redis イメージの Docker インストールと設定手順

目次序文環境インストールMySQLコンテナを作成して起動する落とし穴を避けるための注意MySQLコン...

tomcat ログ ディレクトリ内のログ ファイルの分析 (概要)

tomcat が起動されるたびに、次のログ ファイルがログ ディレクトリに自動的に生成され、日付順...

IE8 互換性について: X-UA-compatible 属性の説明

問題の説明:コードをコピーコードは次のとおりです。 <meta http-equiv=&quo...

MySQL でインデックスとして B+Tree を使用する利点は何ですか?

目次データベースにインデックスが必要なのはなぜですか?インデックスが B+Tree データ構造を使用...

さまざまな MySQL テーブルソートルールのエラーの分析

MySQL が複数のテーブルを結合するときに、次のエラーが報告されます: [Err]1267 – 操...

MySQLでテーブル名を変更する方法と注意すべき点

目次1. テーブル名を変更する方法2. 注記要約: 1. テーブル名を変更する方法RENAME TA...

Mysql GTID Mha 設定方法

Gtid + Mha + Binlog サーバー構成: 1: テスト環境OS: CentOS 6.5...

Windows Server 2016 に Docker をインストールする方法

最近、Microsoft は Docker をネイティブにサポートする Windows Server...

事例を通してLinux NFSの仕組みを詳細に分析

前回の記事に引き続き、web02 サーバーを作成し、web01 サーバーと web02 サーバーの ...

Linux コマンド sort、uniq、tr ツールの詳細な説明

並べ替えツールLinux の sort コマンドは、テキスト ファイルの内容を並べ替えるために使用さ...

Apache での ModSecurity のインストール、有効化、および構成

ModSecurity は、Web サーバーに入るすべてのパケットをチェックする強力なパケット フィ...

MySQL 5.6 zipパッケージのインストールチュートリアルの詳細

これまでは、拡張子が .msi のファイル、つまり、完全なインストールが使用されていました。しかし、...

Vue プロジェクトで TypeScript クラスを適用する方法

目次1. はじめに2. 使用1. @コンポーネント2. 計算、データ、方法3. @props 4. ...

Oracle10パーティションとMySQLパーティションの違いの詳細な説明

一般的に使用される Oracle10g パーティションは、範囲 (範囲パーティション)、リスト (リ...

HTML タグ dl dt dd 使用方法

基本構造:コードをコピーコードは次のとおりです。 <ダウンロード> <dt>...