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 をインストールする詳細なチュートリアル

推薦する

Dockerはコンテナ外のコンテナ内でコマンドを実行します

コンテナ内でコマンドを実行したいが、コンテナに入りたくない場合があります。ではどうすればいいでしょう...

Windows で IP アドレスを指定してサーバーへのリモート アクセスを設定する方法

当社には、外部ネットワークからの干渉を受けることが多いサーバーが多数あります。侵入者はポート 338...

UbuntuはCUDAの複数のバージョンをインストールし、いつでも切り替えることができます

CUDA とは何かを紹介するのではなく、複数の CUDA バージョンの共存とリアルタイム切り替えをど...

一般的な nginx コマンドをシェル スクリプトに組み込む方法の詳細な説明

1. nginxシェルスクリプトを保存するフォルダを作成する /usr/local/タスク/ngin...

MySQL5.7.03 上位バージョンから MySQL 5.7.17 への置き換えインストール プロセスと見つかった問題の解決策

1. インストール方法は? 1. [実行] -> [cmd] と入力して、小さな黒いウィンドウ...

Django+Mysql+Redis+Gunicorn+NginxのDockerデプロイメントの実装

I. はじめにDockerテクノロジーは現在非常に人気があります。コンテナを介してプロジェクト環境を...

RocketMQ の Docker インストールとインストール中に発生した問題の解決策

目次rocketmqイメージを取得する名前rvを作成する単一のブローカーノードを作成するrocket...

CSS セレクターの重みの理解(個人テスト)

コードをコピーコードは次のとおりです。 <スタイル タイプ="text/css&qu...

Innodb システムテーブルスペースのメンテナンス方法

環境説明:実行中の MySQL 環境があります。以前の構成ファイルの設定が単純すぎたため (inno...

Vueのリストレンダリングの詳細な説明

目次1. v-for: 配列の内容を走査する(よく使われる) 2. v-for: オブジェクトのプロ...

Docker+gitlab+jenkins は、ゼロから自動デプロイメントを構築します

目次序文: 1. Dockerをインストールする2. DockerでJenkinsをインストールする...

Linux Cron によるパラメータ付き PHP コードのスケジュール実行

1. 引き続き PHP スクリプトを使用して実行します。コマンドラインに入力: php /home/...

CSS の高度な使い方(実戦で活用)

1. ul タグには、Mozilla ではデフォルトでパディング値がありますが、IE ではマージン値...

CSSの優先度を理解する2つの方法

方法1: 値を追加する公式の説明を見るには MDN にアクセスしてください。優先度はどのように計算さ...

Docker を使用してスタンドアロン Pulsar とクラスター化された Redis をデプロイする方法 (開発アーティファクト)

目次1. はじめに: 2. ドッカー: 1 カスタムネットワーク2 展開を開始する3 ネットワークを...