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

推薦する

Nginx 転送ソケットポート設定の詳細な説明

Nginx によるソケット ポート転送の一般的なシナリオ: オンライン学習アプリケーションでは、通常...

HTML入力で値が変更されたときにリスナーイベントを追加することの簡単な分析

達成される効果多くの場合、入力ボックスの値の変化をリアルタイムで監視し、ブラウザを誘導してウェブサイ...

Vue2.xは、ユーザーのログインと終了を実装するためにルーティングナビゲーションガードを設定します。

目次序文1. ルーティングナビゲーションガードを設定する1. グローバルナビゲーションガード2. ロ...

Alibaba Cloud Server で MySQL デュアルマシン ホットスタンバイを手動で実装する 2 つの方法

1. コンセプト1. ホットバックアップとバックアップの違いホット バックアップは高可用性 (HA)...

mysql charset=utf8 本当に意味が分かりますか

1. まずテーブル作成ステートメントを見てみましょう テーブル学生を作成( sid int 主キー ...

CSS で 2 つの固定列と 1 つの適応列を実装するいくつかの方法

この記事では、CSS で 2 つの固定列と 1 つのアダプティブ列を実装するいくつかの方法を紹介し、...

CSSは半透明の境界と複数の境界のシーン分析を実現します

シナリオ 1:半透明の境界線を実現するには: CSS スタイルのデフォルトの動作により、背景色はコン...

「いいね!」文がインデックスに登録されないのはなぜですか?

序文この記事は、最も人気のある言語で最も退屈な基礎知識を説明することを目的としていますこのトピックは...

Linux テキスト検索コマンド find の詳細な使用方法

find コマンドは主にディレクトリやファイルを検索するために使用され、一致のために複数のパラメータ...

jsで照明スイッチを制御する

参考までに、jsを使用して照明スイッチを制御します。具体的な内容は次のとおりです。トピック: js ...

Linux SSHポートを転送する3つの方法

ssh は私が最も頻繁に使用する 2 つのコマンドライン ツールのうちの 1 つです (もう 1 つ...

WeChat アプレット計算機の例

WeChatアプレット計算機の例、参考までに、具体的な内容は次のとおりです。インデックス.wxml ...

TomcatはNginxリバースプロキシのクライアントドメイン名を取得します

質問Nginx リバース プロキシの後、Tomcat アプリケーションは、クライアント ブラウザーの...

JavaScript でクールなマウス テーリング効果を実装

これを見た後、あなたにも手ができて、さまざまな美しい小さなしっぽを作れるようになることを保証します!...

中国語と英語のフォント名の比較表(FounderとArphicを含む)

CSS ファイルでは、フォント名が文字化けしていることがよくあります。これは、作成者が中国語フォン...