🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JDBC

JDBC(Java DataBase Connectivity)は、Javaとリーレーショナルデータベースに接続させる基本的なAPIです。Java上でSQLステートメントを発行することで、データベースの種類に影響を受ないDB操作を可能とします。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

1回答

6686閲覧

JavaプログラムからMySQLのJDBCドライバを読み込みたい。

na_ka

総合スコア4

JDBC

JDBC(Java DataBase Connectivity)は、Javaとリーレーショナルデータベースに接続させる基本的なAPIです。Java上でSQLステートメントを発行することで、データベースの種類に影響を受ないDB操作を可能とします。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2019/09/06 15:15

編集2019/09/07 04:24

前提・実現したいこと

JavaプログラムからMysqlにJDBCインターフェースで接続すること。

発生している問題・エラーメッセージ

コンパイルは正しく終了したが、実行時に「ドライバを読み込めませんでした java.lang.ClassNotFoundException: com.mysql.jdbc.Driver」になる。

該当のソースコード

Java

1 2import java.sql.Connection; 3import java.sql.DriverManager; 4import java.sql.ResultSet; 5import java.sql.SQLException; 6import java.sql.Statement; 7 8/** 9* localhost上のデータベースと接続し、取得したデータをコンソール出力する。 10*/ 11public class UseJdbc { 12 13 public static void main( String args[] ) throws Exception { 14 15 /*接続先サーバー名を"localhost"で与えることを示している*/ 16 String servername = "localhost"; 17 18 /*接続するデータベース名をsenngokuとしている*/ 19 String databasename = "shop"; 20 21 /*データベースの接続に用いるユーザ名をrootユーザとしている*/ 22 String user = "root"; 23 24 /*データベースの接続に用いるユーザのパスワードを指定している*/ 25 String password = "xxxxxx"; 26 27 /*取り扱う文字コードをUTF-8文字としている*/ 28 String serverencoding = "UTf8mb4"; 29 30 /*データベースをあらわすURLを設定している*/ 31 String url = "jdbc:mysql://localhost/" + databasename; 32 33 /*MySQLの場合、URLの形式は次のようになります。 34 jdbc:mysql://(サーバ名)/(データベース名)*/ 35 36 /*↑データベースをあらわすURL(データベースURL)は、データベースに接続する場合に 37 必要となる情報をセットした文字列である。 38 この文字列の構造は、"jdbc"、サブプロトコル、サブネームの3つの部分から構成される。*/ 39 40 /*接続を表すConnectionオブジェクトを初期化*/ 41 Connection con = null; 42 43 try{ 44 45 /*クラスローダによりJDBCドライバを読み込んでいることを示している。 46 引数は、データベースにアクセスするためのJDBCドライバのクラス名である。*/ 47 Class.forName( "com.mysql.jdbc.Driver" ).newInstance(); 48 49 /*DriverManagerクラスのgetConnectionメソッドを使ってデータベースに接続する。*/ 50 con = DriverManager.getConnection( url, user, password ); 51 52 System.out.println( "Connected...." ); 53 54 /*データベースの接続後に、sql文をデータベースに直接渡すのではなく、 55 sqlコンテナの役割を果たすオブジェクトに渡すためのStatementオブジェクトを作成する。*/ 56 Statement st = con.createStatement(); 57 58 /*SQL文を作成する*/ 59 String sqlStr = "SELECT * FROM busyou"; 60 61 /*SQL文を実行した結果セットをResultSetオブジェクトに格納している*/ 62 ResultSet result = st.executeQuery( sqlStr ); 63 64 /*クエリ結果を1レコードずつ出力していく*/ 65 while( result.next() ) 66 { 67 /*getString()メソッドは、引数に指定されたフィールド名(列)の値をStringとして取得する*/ 68 String str1 = result.getString( "shohin_id" ); 69 String str2 = result.getString( "shohin_mei" ); 70 String str3 = result.getString( "shohin_bunrui" ); 71 String str4 = result.getString( "hanbai_tanka" ); 72 String str5 = result.getString( "shiire_tanka" ); 73 String str6 = result.getString( "torokubi_tanka" ); 74 System.out.println( str1 + ", " + str2 + ", " + str3 + "," + str4+ "," +str5+ "," +str6); 75 } 76 77 /*ResultSetオブジェクトを閉じる*/ 78 result.close(); 79 80 /*Statementオブジェクトを閉じる*/ 81 st.close(); 82 83 /*Connectionオブジェクトを閉じる*/ 84 con.close(); 85 } 86 catch( SQLException e ){ 87 88 /*エラーメッセージ出力*/ 89 System.out.println( "Connection Failed. : " + e.toString() ); 90 91 /*例外を投げちゃうぞ*/ 92 throw new Exception(); 93 94 }catch (ClassNotFoundException e){ 95 96 /*エラーメッセージ出力*/ 97 System.out.println("ドライバを読み込めませんでした " + e); 98 } 99 finally{ 100 try{ 101 if( con != null ){ 102 con.close(); 103 } 104 } 105 catch(Exception e){ 106 107 /*エラーメッセージ出力*/ 108 System.out.println( "Exception2! :" + e.toString() ); 109 110 /*例外を投げちゃうぞ*/ 111 throw new Exception(); 112 } 113 } 114 } 115}

試したこと

mysql-connector-java-8.0.17.jarをダウンロードし、Usejdbcクラスと同じディレクトリに格納したが、結果は同じでした。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xebme

2019/09/06 22:10

クラスパスにmysql-connector-java-8.0.17.jarが含まれていますか?質問にクラスパスを追記してください。うまく動作したなら、Class.forName()を削除して実行してみてください。
退会済みユーザー

退会済みユーザー

2019/09/06 23:35

あと今のJDBC技術は4.0以降です。 3.x系のコードをサンプルにするのはやめましょう。
xebme

2019/09/07 01:38

まともに答えたいのですが情報が不足しています。IDE、Java、ドライバーのバージョンは?、IDEではなくオンラインの実行環境でしょうか?コンパイルと実行はどのように行っていますか。このプログラムはどこから入手しましたか?書籍なら書籍名を、どこかの教材なら開示できる範囲で、教えてください。
na_ka

2019/09/07 04:27

ご指摘ありがとうございます。 mysql-connector-java-8.0.17.jarは、ソースと同じフォルダにあるのでクラスパスは指定しませんでした。 指定して下記の通り実行しました。 javac -classpath ¥mysql-connector-java-8.0.17.jar Usejdbc.java 警告メッセージは出ましたが、オブジェクトはできたので、実行しました。 java -classpath ¥mysql-connector-java-8.0.17.jar Usejdbc 「エラー: メイン・クラスUsejdbcが見つからなかったかロードできませんでした」になりました。 IDEは、CPad for Java2 SDKを使用しました。 Jdkは11.0.2 コンパイルは、CPad for Java2 SDKとコマンドプロンプトの両方で行いました。Mysql(xampp MariaDB)のバージョンは、10.3.16.0です。 本プログラムは、https://qiita.com/norikiyo777/items/0bc3bf28b94ae4922b9aを修正しました。 jdbc接続は初めてなので苦労しています。 よろしくお願いいたします。
xebme

2019/09/07 04:52

クラスパスにカレントディレクトリを含めてください。クラス名が間違っています。 java -classpath .;mysql-connector-java-8.0.17.jar UseJdbc このプログラムはレガシーコードです。もはや使われていません。
na_ka

2019/09/07 05:58

正しく実行しましたが、以下のエラーになりました。 Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.UnsupportedClassVersionError: UseJdbc has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(Unknown Source) at java.security.SecureClassLoader.defineClass(Unknown Source) at java.net.URLClassLoader.defineClass(Unknown Source) at java.net.URLClassLoader.access$100(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source) ------------------------------------------------------------------------- >java -version java version "1.8.0_202" Java(TM) SE Runtime Environment (build 1.8.0_202-b08) Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode) ------------------------------------------------------------------------- java runtimeが古いのでしょうか?
xebme

2019/09/07 08:08 編集

echo %PATH% パスの先頭にJRE 8があり、パスの後にJDK 11があると思われます。Windowsのシステム環境設定で、JREのパスを削除するか、とりあえず、PATH=<jdk11のパス>;%PATH%として実行してください。JDK 8 のインストーラが、先頭にJREのパスを追加してしまうのでこうなります。
guest

回答1

0

レガシーコード
参考にしているソースはレガシーコードです。このソースを参考にしてはいけません。このソースを、JDK 11 を使ってコンパイルします。私の環境はLinux、ドライバーの場所は /usr/share/java/mysql-connector-java.jar

bash

1$ javac -cp .:/usr/share/java/mysql-connector-java.jar UseJdbc.java 2注意:UseJdbc.javaは推奨されないAPIを使用またはオーバーライドしています。 3注意:詳細は、-Xlint:deprecationオプションを指定して再コンパイルしてください。

警告(Java 9より表示)が出てもここでは重要ではない。クラスファイルができているので実行します。

bash

1$ java -cp .:/usr/share/java/mysql-connector-java.jar UseJdbc 2Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary. 3Connection Failed. : com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure 4 5The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. 6Exception in thread "main" java.lang.Exception 7 at UseJdbc.main(UseJdbc.java:91)

実行すると警告がでます。警告文の意味です。

  • com.mysql.jdbc.Driverは廃止される予定。新しいドライバーはcom.mysql.cj.jdbc.Driver。
  • ドライバーはSPIを介して自動的に登録されるので、ドラーバーを手動でロードする必要はない。

com.mysql.jdbc.Driverは、staticイニシャライザーがこの警告文を出すためだけに存在します。それ以外何もしません。com.mysql.cj.jdbc.Driver が自動ロードされています。

その次のエラーは、mariadbサーバーが起動していないのでネットワークエラー。データベースが正常に動作すれば結果が出力されます。

[学習してほしいこと]

  • Java 6 以降では、JDBC 4がサポートされ、CLass.forName()は不要になった。(後方互換のために残される)
  • Java 7 より、AutoCloseableインターフェイスがサポートされ、リソースの明示的な閉じは不要になった。
  • Java 9 より、try-with-resources 構文が拡張された。

これを踏まえたソースを示します。

Java

1public static void main(String args[]) { 2 3 String servername = "localhost"; 4 String databasename = "shop"; 5 String user = "root"; 6 String password = "nakaha11"; 7 8 String url = "jdbc:mysql://" + servername + "/" + databasename; 9 10 try (Connection con = DriverManager.getConnection(url, user, password)) { 11 System.out.println("Connected...."); 12 try (Statement st = con.createStatement()) { 13 String sqlStr = "SELECT * FROM busyou"; 14 try (ResultSet result = st.executeQuery(sqlStr)) { 15 while (result.next()) { 16 String str1 = result.getString("shohin_id"); 17 String str2 = result.getString("shohin_mei"); 18 String str3 = result.getString("shohin_bunrui"); 19 String str4 = result.getString("hanbai_tanka"); 20 String str5 = result.getString("shiire_tanka"); 21 String str6 = result.getString("torokubi_tanka"); 22 System.out.println(str1 + ", " + str2 + ", " + str3 + "," + str4 + "," + str5 + "," + str6); 23 } 24 } 25 } 26 } catch (SQLException e) { 27 System.out.println("Connection Failed. : " + e.toString()); 28 throw new RuntimeException(e); 29 } 30} 31

注意事項

  • Webアプリケーションでは、WEB-INF/lib配下にドライバーを配置すると、SPI機能が使えずドライバーがロードされません。仕方がないので、Class.forName()するのがあたりまえだと思われていますが、問題が起きる可能性があるので避けるべきです。
  • 質問のJavaアプリケーションでは、SPI機能が働くので、Class.forName()は書いてはいけません。

(タイムゾーンエラー)2019-09-15

私のLinux環境では発生しないので、Windowsにサーバーをインストールました。JDBCのエラーメッセージは、サーバーのタイムゾーンの名前が不明または複数存在する、です。解決方法も書かれています(以下のどちらか)。

  • サーバーのタイムゾーンを設定する
  • JDBCドライバーのserverTimezoneプロパティを設定する

JavaプログラムでserverTimezoneを設定する解決法

コメントしたとおり、urlの末尾に"?serverTimezone=JST"を追加してください。

Java

1String url = "jdbc:mysql://" + servername + "/" + databasename + "?serverTimezone=JST";

サーバーのタイムゾーンを設定する解決法

管理者権限でmy.iniを変更。間違えるとサーバーが起動しなくなります。参考: MariaDB (MySQL) のタイムゾーン、タイムゾーンテーブルを設定する

A. WindowsのMySQLサーバー用パッケージ: MySQL Community Downloads
バージョン5.7+ のパッケージ(timezone_2019c_posix_sql.zip)をダウンロード。圧縮解除する。以下のコマンドでタイムゾーン情報を取り込む。

dos

1> mysql -u root -p mysql < timezone_posix.sql

B. 管理者権限でmy.iniを変更

  1. MySQLサービスを停止
  2. ProgramData\MySQL\MySQL Server 5.X\my.iniを[管理者権限で編集]バックアップ必須。[mysqld]グループの末尾に1行追加。

my.ini

1default-time-zone='Asia/Tokyo'
  1. MySQLサービスを起動

C. MySQLクライアントを起動、設定を確認。タイムゾーンが設定した名前になっていること。

> mysql -u root -p mysql> show variables like '%time_zone%'; +------------------+------------+ | Variable_name | Value | +------------------+------------+ | system_time_zone | | | time_zone | Asia/Tokyo | +------------------+------------+

サーバーで設定すれば、JavaプログラムのJDBC接続プロパティは不要です。

投稿2019/09/07 06:44

編集2019/09/15 05:05
xebme

総合スコア1090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

na_ka

2019/09/07 08:11

いろいろとご丁寧に教えていただきありがとうございました。JDBCを勉強し、いただいたソースをベースにさせていただきます。
na_ka

2019/09/11 15:08

確認が遅れました。申し訳ありません。教えていただいたソースを基に実行したところ、timezoneのエラーになりました。 「Connection Failed. : java.sql.SQLException: The server time zone value 'unknown' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support. Exception in thread "main" java.lang.RuntimeException: java.sql.SQLException: The server time zone value 'unknown' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.」修正方法が分からないので教えてください。作成したソースは下記です。よろしくお願いいたします。 --------------------------------------------------------------------------- import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class main { public static void main(String args[]) { String servername = "localhost"; String databasename = "shop"; String user = "root"; String password = "123456"; String url = "jdbc:mysql://" + servername + "/" + databasename ; try (Connection con = DriverManager.getConnection(url, user, password)) { System.out.println("Connected...."); try (Statement st = con.createStatement()) { String sqlStr = "SELECT * FROM busyou"; try (ResultSet result = st.executeQuery(sqlStr)) { while (result.next()) { String str1 = result.getString("shohin_id"); String str2 = result.getString("shohin_mei"); String str3 = result.getString("shohin_bunrui"); String str4 = result.getString("hanbai_tanka"); String str5 = result.getString("shiire_tanka"); String str6 = result.getString("torokubi_tanka"); System.out.println(str1 + ", " + str2 + ", " + str3 + "," + str4 + "," + str5 + "," + str6); } } } } catch (SQLException e) { System.out.println("Connection Failed. : " + e.toString()); throw new RuntimeException(e); } } } ------------------------------------------------------------------------
xebme

2019/09/11 20:20

参考です。"jdbc:mysql://localhost/shop?serverTimezone=JST" 解決方法は、探せばいくらでも見つかると思います。ぜひ自力で解決してください。
退会済みユーザー

退会済みユーザー

2019/09/12 23:21

後方互換のために残されたわけではありません。 メタファイルでクラス名を特定して自動でリフレクションのclass.forName呼ぶようになっただけです。
xebme

2019/09/12 23:43

おっしゃっているのは、META-INF/service/... のことだと思います。ServiceLoaderの機能ですね。「後方互換」という言葉を間違えたことに気づきました。「下位互換」とすべきでした。ありがとうございます。
xebme

2019/09/13 04:48

補足します。『timezoneのエラーになりました』はドライバーがロードされた後に、サーバー接続で起きる問題。接続URLにパラメータを追加すれば解決できます。回答を追記するのは調べてから。早くて日曜日の夕方以降。
na_ka

2019/09/15 14:20

ご丁寧な回答ありがとうございました。おかげさまで無事実行できました。感謝申し上げます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問